Wednesday, November 09, 2011

Refactoring MVC Routes

Some of my team members and myself are participating in the Houston AIR competition this weekend and we are building our project this week. Of course we’ll have to rebuild it from scratch on Saturday, but hopefully it’ll just be a bunch of re-typing and no surprises. Anyhow, one of my duties on the team is to configure MVC and the interfaces we’ll need and all that jazz. So when I went to setup the routes, I was surprised again at how flexible it all is to setup. Typically you can get by with the default route, but not in our case this time. Basically we wanted to have these routes:

/story/give
/story/{id}
/feature/{id}
/prayer/{id}
/{pagename}

By the way, our assigned charity is a church in Houston called the Household of Faith Church - South Acres. At first I had this: (which is TOTALLY RIDCULOUS, but I wanted to see them all)
routes.MapRoute(
"Home",
"",
new { controller = "Main", action = "Home" });

routes.MapRoute(
"GiveStory",
"give/story",
new { controller = "Main", action = "GiveStory" });

routes.MapRoute(
"Feature",
"feature/{id}",
new { controller = "Main", action = "Feature", id=UrlParameter.Optional });

routes.MapRoute(
"Prayer",
"Prayer/{id}",
new { controller = "Main", action = "Prayer", id = UrlParameter.Optional });

routes.MapRoute(
"Story",
"Story/{id}",
new { controller = "Main", action = "Story", id = UrlParameter.Optional });

routes.MapRoute(
"About",
"About",
new { controller = "Main", action = "About"});

routes.MapRoute(
"Directions",
"Directions",
new { controller = "Main", action = "Directions" });

routes.MapRoute(
"SiteMap",
"SiteMap",
new { controller = "Main", action = "SiteMap" });

routes.MapRoute(
"Help",
"Help",
new { controller = "Main", action = "Help" });
I typically setup my routes early on because I usually know what I want the URLs to be and it helps when naming my actions on the controllers. So obvioulsy we only have one controller because it’s not a large site and they all kinda go together, but what’s up with all the actions on the route configuration? Ridiculous right? So let’s get rid of all that mess like this:
routes.MapRoute(
"GiveStory",
"give/story",
new { controller = "Main", action = "GiveStory" });

routes.MapRoute(
"Feature",
"feature/{id}",
new { controller = "Main", action = "Feature", id=UrlParameter.Optional });

routes.MapRoute(
"Prayer",
"Prayer/{id}",
new { controller = "Main", action = "Prayer", id = UrlParameter.Optional });

routes.MapRoute(
"Story",
"Story/{id}",
new { controller = "Main", action = "Story", id = UrlParameter.Optional });

routes.MapRoute(
"Page",
"{viewname}",
new { controller = "Main", action = "GetStatic", viewname = "Home" });
Simple enough right? So I created an action called GetStatic that just accepts the view name for that page. The action looks like this:
public ViewResult GetStatic(string viewname)
{
return View(viewname);
}
Now let’s address the other redundant mess I have here…the {feature/prayer/story}/{id} route. Basically we’re going to do that and add a constraint to the route like this:
routes.MapRoute(
"GiveStory",
"give/story",
new { controller = "Main", action = "GiveStory" });

routes.MapRoute(
"WebSectionRoute",
"{WebType}/{Id}",
new { Controller = "Main", action = "GetWebSection", Id = UrlParameter.Optional }, new {WebType = "Story|Feature|Prayer"});

routes.MapRoute(
"Page",
"{viewname}",
new { controller = "Main", action = "GetStatic", viewname = "Home" });
So what this says is if the WebType contains story/feature/prayer then use this route otherwise keep on going. I can’t express enough the importance of the route order here. It’s an easy thing to miss and I’ve caught the missed order a few times for other developers and myself. Make sur eyou put them in the order they need to be in and not in some random order. Well that’s it. Route configuration refactored and now it doesn’t have any redundant routes.

Thanks for reading!

kick it on DotNetKicks.com

Sunday, October 16, 2011

How to easily turn your L2S objects into interfaces




I know it’s been a while since I posted an actual post, but I think this one will be fun. So let’s get to it…
In one of our recent code reviews, we found several methods that looked almost identical. All of these methods were just for lookup tables that populated a dropdown. So…this is what we did:
We had a repository with something like GetDepartmentList and GetStatusList that looked something like this:
public class SampleRepository : ISampleRepository
    {
        public IList<LookupDepartment> GetDepartmentList()
        {
            using (var dc = new LookupSampleDataContext())
                return dc.LookupDepartments
                                 .Where(x => !x.IsDeleted)
                                 .OrderBy(x=>x.Name)
                                 .ToList();
        }

        public IList<LookupStatus> GetStatusList()
        {
            using (var dc = new LookupSampleDataContext())
                return dc.LookupStatus
                                 .Where(x => !x.IsDeleted)
                                 .OrderBy(x=>x.Status)
                                 .ToList();
        }
    }
Note: we do not return L2S objects typically, but to make this example simple, I’m going to pretend that we do.
The first thing we did was changed the type returned by both methods to return ILookupObject instead of the L2S objects…like this:
public class SampleRepository : ISampleRepository
    {
        public IList<ILookupObject> GetDepartmentList()
        {
            using (var dc = new LookupSampleDataContext())
                return dc.LookupDepartments
                                 .Where(x => !x.IsDeleted)
                                 .OrderBy(x=>x.Name)
                                 .Cast<ILookupObject>()
                                 .ToList();
        }

        public IList<ILookupObject> GetStatusList()
        {
            using (var dc = new LookupSampleDataContext())
                return dc.LookupStatus
                                 .Where(x => !x.IsDeleted)
                                 .OrderBy(x=>x.Status)
                                 .Cast<ILookupObject>()
                                 .ToList();
        }
    }
Obviously this cast isn’t going to work so we need to finagle our dbml. It’s easy to extend the L2S objects without modifying the dbml. I actually prefer never to touch the dbml itself unless absolutely necessary because I like to Ctrl+A, del, drag everything back over whenever I want :)
So to extend the classes, we just need to do this:
public partial class LookupDepartment : ILookupObject
    {
        public string DisplayName { get { return Name; } }
    }

    public partial class LookupStatus : ILookupObject
    {
        public string DisplayName { get { return Status;} }
    }
Done.
Now we need to revisit our SampleRepository and extract out all the redundant code so we have something like this:
private static IList<ILookupObject> GetList<T>(Expression<Func<T, object>> orderby) where T : class, ILookupObject
        {
            using (var dc = new LookupSampleDataContext())
                return dc.GetTable<T>()
                                 .Where(x => !x.IsDeleted)
                                 .OrderBy(orderby)
                                 .Cast<ILookupObject>()
                                 .ToList();
        }
All we’ve done is made a generic GetList method that takes in the orderby. You could easily make this not dependent on the datacontext too, but to keep this post simple, we won’t do that now. As you can see, this looks almost exactly like our original method with the exception of dc.GetTable<T>(), which is built-in to the datacontext class. All we need to do is pass it the type so it knows from which table to pull data. It’s actually a pet peeve of mine for a lookup type dropdown to not be ordered, so I’m forcing the orderby method and not giving another option.
The repository looks like this now:
public class RefactoredSampleRepository : ISampleRepository
    {
        private static IList<ILookupObject> GetList<T>(Expression<Func<T, object>> orderby) where T : class, ILookupObject
        {
            using (var dc = new LookupSampleDataContext())
                return dc.GetTable<T>()
                         .Where(x => !x.IsDeleted)
                         .OrderBy(orderby)
                         .Cast<ILookupObject>()
                         .ToList();
        }

        public IList<ILookupObject> GetDepartmentList()
        {
            return GetList<LookupDepartment>(x=>x.Name);
        }

        public IList<ILookupObject> GetStatusList()
        {
            return GetList<LookupStatus>(x=>x.Status);
        }
    }
Nice and pretty…I don’t like the orderby expression here, but I think it’s the best option for now. There is another way, but it jacks up L2S for inserts and updates. So, if you KNOW your not going to ever update or insert a new record for a lookup, then you could do this:
public partial class LookupStatus : ILookupObject
    {
        [Column(Name="Status")]
        public string DisplayName { get; set; }
    }
What this does is maps the DisplayName to the Status column so you could just do .OrderBy(x=>x.DisplayName) instead of passing in the orderby. The reason you have to map the column is because you’ll get a “SQL has no supported translation…” error. You could also just rename the property Status to DisplayName in the dbml file itself.
Also, it’s not recommended that you use multiple datacontexts according to l2sprof, but to make this simple, I did.
So now we can easily bind this to a dropdown via another helper method like this:
public static class extensions
    {
        public static void BindDropDownTo(this DropDownList ddl, IList<ILookupObject> data)
        {
            ddl.DataSource = data;
            ddl.DataTextField = "DisplayName";
            ddl.DataValueField = "ID";
            ddl.DataBind();
        }
    }
So in the UI, we just do this: (if using webforms)
ddlStatus.BindDropDownTo(rep.GetStatusList());
If you’re using MVC, you could create an htmlhelper to do something similar.
Alright, I think that’s it. Please post if you have better methods or have any questions.
Thanks for reading!
Shout it

kick it on DotNetKicks.com

Sunday, October 09, 2011

Can't believe it...

A whole month went by without me realizing that I didn't blog. It's insane to me how fast a month goes by these days. I'm going to have to step up my blogging again.

At least vacation time is coming up soon, so I'll have more free time.

kick it on DotNetKicks.com

Thursday, August 25, 2011

Blogging just to Blog…I mean Styling Tips!




Lately I have not felt like blogging, but I’m committed to at least once a month. I think the primary reason I haven’t felt th need to blog is because I haven’t really spent much time developing lately. I’ve been spending a lot of my time on user experience and interface design.

I thought I’d share a few styling tricks that are too easy not to do because they add a lot to usability.

  1. Changing the style of a row on hover. This allows the end user to easily see which row they’re looking at instead of having to trace the line.

    table tr:hover td {background: #e7e7e7}
  2. Changing the style of an input on focus. This allows the end-user to easily see where they’re at in a form without much thought.

    input:focus {border: solid 1px #f90}
  3. Changing the style of a hyperlink on hover. Granted this one has been around forever, but it’s a great one.

    a:hover {background: #333; color: #fff}

There are most definitely hundreds more, but these are a few of my favorites to use on a project. Also note that they do NOT work in all browsers.

Thanks for reading!

kick it on DotNetKicks.com

Monday, July 18, 2011

Big Design Conference 2011 Recap




Once again I find myself writing a conference recap without notes. Let me go ahead and apologize to all the speakers just in case I leave out something or misunderstood their presentation.

So…this year’s conference wasn’t as good as last year’s to me. I think there are a few reasons…

1. No free donuts (even though I didn’t care for the orange topping last year…I still liked them…I mean, they’re donuts)

2. No free sodas and snacks between sessions. These are important for any successful conference in my opinion :)

3. It wasn’t all new to me…I knew more of what to expect and what people were going to talk about…not the case last year.

As for the presentations, I’m unsure if they were the same or not as good because I lost perspective as a non-conf-rook. Everything last year was new and fresh and this year, not so much. This year’s conference theme was more about all your customer experiences meshing into one big great customer experience via whatever outlet…last year there seemed to be more of a theme on how to leverage the social web. Anyhow, if you’d like to read that recap you can here.

Day 1:

  • Keynote by Gwen Harmon (@ncrmuseum)
    What I took away…
    • Emotional design makes the whole experience almost life haltering, even if temporarily.
    • The National Civil Rights Museum looks like an amazing place to go visit.
    • Engineers are honest to the point of their own death. I had never heard this joke, it was funny.
      • The Joke: an engineer, a lawyer, and a something else(should’ve taken notes) are all on death row via guillotine. The something else is up, they release the blade and it stops…so he’s let off…the lawyer gets up there the blade drops and it stops again…so he’s let off…the engineer has his turn and looks up and says oh I see your problem.
    • The National Civil Rights Museum is looking to do a lot of upgrades, which will make it even more appealing to visit and learn. You can donate now if you’d like to help.
  • Mobile Design at the Speed of Thought by Michael Griffith @crypticdevice
    Prezi Show
    What I took away…
    • Two ways to communicate – talking & drawing (i.e. not reading requirements)
    • Ideas are disposable…we’ll make more!
    • Downloaded the 106 & Park iPhone app. Played with the voting “game”…highest thus far…30 votes
    • Don’t turn a website into an app! An app is a companion to a website.
    • Buy this book…Understanding Comics The Invisible Art by Scott McCloud
      Also…I bought this book…and 5 others…stupid conference making me spend $
  • Designing a Cohesive Customer Experience by Elizabeth Rosenzweig (@elizrosenzweig) and Scott Gunter
    What I took away…
    • Get to sessions on time because standing for an hour kinda sucks
    • With that said, I know they were talking a lot about Ikea…but I missed most of that part…
    • Don’t shop at Pottery Barn because they will stalk you…at least one of the audience members made it sound this way…I believe it
    • Apparently we are capable of cloaking something for 3 nano seconds according to Elizabeth via MSNBC. Read more here if you wish
    • The jist of this one was to make all of your customer experiences aware of each other…if I create a shopping list on kroger.com and it knows which store I shop at…give me my list on my phone by aisle and sort it based on location so I don’t do 18 laps around the store…seriously they should do this…
  • Free Your Mind: Using UX Checklists to Focus on What's Important by Elisa Miller (@elisakm)
    Download Slide Deck
    What I took away…
    • Make good checklists
    • Buy this book - The Checklist Manifesto by Atul Gawande. (Recommended in more than one presentation I attended)
    • I actually started making quite a few checklists today…the most important: Post-Deployment Review Checklist for applications team
  • Forget your MBA: Managing in a Creative Culture by Marcelo Somers (@marcelosomers)
    Download Slide Deck
    What I took away…
    • He’s a finance geek and a machead
    • Companies are alive and they don’t live very long
    • Focus on a few things and do them better than anyone else…Chipotle was his example
    • The market changes…either change with it or die
  • Designing for Disabilities by Sharron Rush (@sharrush)
    What I would’ve taken away…
    • I’ll admit it…I went for a nap over another session…HOWEVER, I would’ve gone to this one. I did stop by their booth because I plan to participate in their airhouston event in October and was looking for more info. I went to her session last year and it was very eye opening. Seriously, I literally just read the description and am very sorry I missed this one. (Sure wish the description had been on some form of program rather than a print out with titles…hint hint!)
  • Closing Keynote by Russ Unger (who needs no introduction apparently, but gets one anyhow cause he’s special) (@russu)
    What I took away…
    • Russ is very happy. (last year he was angry so whatever he’s doing is working apparently)
    • Russ is writing another book with Todd Zaki Warfel. Guerrilla UX Research Methods released November 15, 2011 according to Amazon.com
    • Russ is still funny.
    • Russ grew a “Texas” mustache just for us
    • Russ thinks we should adopt Ice UX Framework…
      • stop collaborate and listen
      • anything less than the best is a felony
      • quick to the point to the point no faking
      • and there may have been others
    • Russ likes a cat named Maru that gets into small boxes…the cat is funny
    • Russ doesn’t know what he does for a living…or maybe people that he is close to don’t know…I don’t remember if he ever actually said
    • Russ is excited to see what we do…I’m curious and a little excited too :)

Day 2:

  • Opening Keynote by Josh Clark (@globalmoxie)
    • I slept in due to lack of description. I need to know what I’m waking up for :)
  • Accelerated Style Sheets: Less Typing, More Style by Wynn Netherland (@pengwynn) and Nathan Smith (@nathansmith)
    • Intended to go to this, but was caught up with packing and checking out of my room
  • Designing for Change and Innovation by Sara Summers (@sarasummers)
    What I took away…
    • She wrote a book. I was going to buy it, but then I saw it was using Expression Blend…
    • Use your conference waiting time to ask people about ideas you have
    • Make a feedback area in the blank walls of the surrounding cubes
    • Walk the dog to think or actually just make time to think – I actually did that this morning on my way into work. I have a 45 minute commute and left the radio off so I could think…it was nice to talk to me.
  • Innovation: Ideas are Just the Beginning by Adam Polansky (@adamtheia)
    Download Slide Deck
    What I took away…
    • An extra 30 minutes to look around…he was a bit quick
    • Innovation = New Combinations (i.e. guy driving thinks “I like listening to radio”…”HEY NOW! I should add a radio in my car!”)
    • Create a list of small bug fixes that can be fixed on your own time…present them…they’ll probably get added to the project list
  • Slay the Legacy Code Beast by Caleb Jenkins (@calebjenkins)
    Download Slide Deck
    What I took away…
    • Caleb is here to help.
    • Caleb looks and talks a LOT like Dane Cook (I think Caleb might be funnier)
    • Caleb references presentations from a year ago (I should’ve gone I guess)
    • Caleb likes to ROOOOAAARRR (or just make monster noises…not sure how to spell what he was doing) and he enjoys audience participation
    • Caleb once worked on a solution with over 68 projects…I think I woulda quit
    • Here’s the jist:
      • Know Your Foe (Legacy Code)
        • Don’t go changing stuff willy nilly
        • Use dependency graphs
      • Create a Safety Net
        • Use Source Control
        • Create Tests
      • Divide and Conquer (pick your battles)
        • The slideshare.net doesn’t do his presentation justice…I mean there was a really nifty split of the screen for this 3rd strategy announcement during his live presentation…it was truly amazing.
    • Caleb will give you credit if he takes one of your pics from flickr…good to know
    • I really enjoyed Caleb’s talk even though I don’t have every day battles with legacy monsters
  • Designing for Awareness by Brian Sullivan (@BrianKSullivan) and Taylor Cowan (@tcowan)
    Download Slide Deck
    What I took away…
    • Attention = Focus
    • Distraction = Disorder
    • Information’s price is attention…don’t be poor on attention
    • Two types of attention…active and passive
    • Do you multi-task? No you don’t.
    • Checklists mentioned again
    • Interruption vs Notification – Very important in design
      • Interruption = Active Awareness (i.e. alert(‘Hey there!’);)
        • Only in emergency or dire situation
      • Notifications = Passive Awareness (i.e. $(‘#thissmallredsquarenotification’).show();)
    • We process 400 billion bits of data per second passively
      • A lot less actively…2,000
  • Progressive Prototyping with HTML5, CSS3, and jQuery by Todd Zaki Warfel (@zakiwarfel)
    Download Slide Deck
    What I took away…
    • Todd likes to cook
    • Todd makes grayscale look sexy
    • Todd does not wireframe…I still do…I prototype too…mostly I wireframe to help me visualize the markup and gen the graphics
      • Todd does this via sketches…I’m not that good
      • I wonder what kind of markers he uses because they look like some awesome colors on his slideshow
    • Todd prefers to fail in a low cost environment…imagine that…
    • Todd lays out the data first…then he styles
    • Todd bragged a lot about not having a single image on his grayscale and it still looking “sexy”
    • Todd then went on about the awesomeness of HTML5
      • Specifically the progress and meter tags, which are pretty freakin sweet
    • Todd gave a heads up about updating your reset.css…I’m glad he did because I have not
    • Todd provides great coverage of CSS3 Selectors…I’ll let you look at his deck…same with his jQuery coverage
    • Todd wrote a book and is working on the one mentioned earlier with Russ Unger…I bought the Prototyping book and am reading it now
  • Mobile & UX by Jared Spool
    Download Slide Deck…OH wait I haven’t received it via email yet…hopefully I emailed them correctly and will get it soon and hopefully I can get permission to share…if not…you shoulda been there :)
    What I took away…
    • Jared is flippin smart.
    • Jared is great at teaching and entertaining…not once did I think, “hey! I’m learning a lot” (I did though)
      • Sturgeon’s Law – 90% of everything is crap. Are you in the 10%?
      • Technology » Features » Experience
        • Jared realizes on an example here that his audience is a young one
      • The Kano Model
        • User Satisfaction by Company Investment
        • Must meet basic expectations (BEs) before excitement generators work
          • When BEs don’t work, you’re just pissing people off
          • With time, delighters become BEs
      • There were 3 questions to see how well formed your team is…but I don’t remember them. Hopefully I get that slide deck soon :)
        What I remember…
        • the vision of the team and their experience with your design
        • how long you spend watching your’s or your competitor’s design
        • have you rewarded failure
    • We are in an immature era, we are learning and the next few years are going to be very exciting and a bit scary if you like your privacy. Seriously…scary.

Books Bought Due to Conference:

Other Stuff

Suggestions for next year

  1. Printed programs with full descriptions of presentations and speakers
  2. Donuts
  3. Snacks
  4. Sodas
  5. Casino night that I know about at least a day or two before the night actually occurs…I would’ve loved to shoot some craps
  6. Donuts
  7. Maybe some bacon??

That about does it. I enjoyed the conference and I’m excited about the user experiences I’ll be creating in the next year. Look forward to next year’s event!

Thanks for reading!

kick it on DotNetKicks.com

Thursday, June 16, 2011

jQuery Plugin: FunkyFocus v1.1


I used by little plugin in a production environment today and found one bug and a couple needed features.

The bug was with this code:

options.selectorOverride.replace('{id}', this.id);
 
Apparently it only replaces the first {id} found in the string. So I updated that line to this:
 
var selector = options.selectorOverride.replace(/{id}/gi, this.id);

One of the features I needed was a way to ignore certain elements. So I created a new option called notSelector and the default is ‘.ignore’. So basically all the selectors are $(selector).not(options.notSelector).whatever.

I also added a check for when you set the focus of an input via the code-behind in ASP.NET.

You can download the new version here.

Check out the demo here.

Thanks for reading!

kick it on DotNetKicks.com

Thursday, May 26, 2011

New jQuery Plugin: FunkyFocus


So this jQuery plugin was built to help my end-users know immediately what section of a form they’re working on. Also, don’t blame me for the name. It was given to my new plugin by my wife because I couldn’t think of anything “catchy”. Basically what this thing does is changes the background of sections of forms or individual inputs. It’ll be better to post screenshots to get the idea…so…here you go…

image

So as soon as you tab to the password textbox, you get this:

image

Here’s how you use it:

  1. Add a reference to jQuery
  2. Add a reference to the jquery.funkyfocus.js
  3. Add this line afterward: $('form').funkyFocus();

If you want to customize how you use it, you have some options. Here they are:

  • class – default is selected
  • sectionOnly – default is true
  • selectorOverride – default is form#{id} input,form#{id} select,form#{id} textarea

If you don’t want to use selected as your class, you’d use this code:

    $('form').funkyFocus({class: 'yourclassname'});

If you don’t want to change the background, but want to change the individual input, do this:

    $('form').funkyFocus({sectionOnly: false});

It would look something like this (assuming you changed the selected style to have a green background):

image

Here’s the actual plugin code:

(function($) {
    $.fn.funkyFocus = function(options) {
  var defaults = {
    class: 'selected',
    sectionOnly: true,
    selectorOverride: 'form#{id} input,form#{id} select,form#{id} textarea'
  };
  var options = $.extend(defaults, options);
  return this.each(function() {
    var selector = options.selectorOverride.replace('{id}', this.id);
    $(selector).focus(function() {
      if (options.sectionOnly)
        $(this).closest("div").addClass(options.class);
      else
        $(this).addClass(options.class);
    });
    $(selector).blur(function() {
      if (options.sectionOnly)
        $(this).closest("div").removeClass(options.class);
      else
        $(this).removeClass(options.class);
    });
        });
    };
})(jQuery);

If you’d like to know how to create a jQuery plugin, check out this post.

Download the plugin here.

Check out the demo here.

As always, please let me know if there’s a way to improve it. Thanks for reading!

Shout it

kick it on DotNetKicks.com

Related Posts Plugin for WordPress, Blogger...