in

Platinum Bay

Peace, Love, and...

This Blog

Syndication


.NETicated

  • Modifying Tree Node Text in the Umbraco Backend

    I’m currently working on rebuilding the http://dotnetda.org site using Umbraco and I have created the usual assortment of document types: speakers, meetings, sponsors, etc. For meetings, the name of the node is simply the session title. Unfortunately, this means that finding a meeting requires knowing the session title and I want the node text to be more descriptive and include the date as well. I can use the Umbraco API and write a little code to do this for me.

    To start, I added the following using statements:

    using System;
    using umbraco.BusinessLogic;
    using umbraco.cms.businesslogic;
    using umbraco.cms.presentation.Trees;

    Then, I created a class that inherits from ApplicationBase. By simply inheriting from ApplicationBase, Umbraco will automatically load the class during initialization:

    public class TreeEvents : ApplicationBase
    {
    }

    Next, I added a TreeEvents constructor and handled the BaseTree.BeforeNodeRender event:

    public TreeEvents()
    {
        BaseTree.BeforeNodeRender += BaseTree_BeforeNodeRender;
    }

    And finally I implemented the BaseTree_BeforeNodeRender method with the necessary logic to update the node’s Text property if it’s a meeting:

    void BaseTree_BeforeNodeRender(
        ref XmlTree sender, ref XmlTreeNode node, EventArgs e)
    {
        if (node.NodeType == "content")
        {
            var content = new Content(int.Parse(node.NodeID));
    
            if (content.ContentType.Alias == "Meeting")
            {
                var startDate = content.getProperty("meetingStartDate")
                    .Value.ToString();
    
                var date = DateTime.Parse(startDate);
                node.Text = String.Format("{0:MM/dd/yyyy} {1}",
                    date,
                    node.Text
                    );
            }
        }
    }

    First, I ensure that I’m dealing with a content node, then I grab the content item based on NodeID. If the content type alias is Meeting, I parse the meetingStartDate property and prepend it to the node’s existing text.

    The final result is that I can now see the meeting date which will make meetings much easier to find:

    image

    Final Code

    using System;
    using umbraco.BusinessLogic;
    using umbraco.cms.businesslogic;
    using umbraco.cms.presentation.Trees;
    
    namespace Netda.Umbraco
    {
        public class TreeEvents : ApplicationBase
        {
            public TreeEvents()
            {
                BaseTree.BeforeNodeRender += BaseTree_BeforeNodeRender;
            }
    
            void BaseTree_BeforeNodeRender(
                ref XmlTree sender, ref XmlTreeNode node, EventArgs e)
            {
                if (node.NodeType == "content")
                {
                    var content = new Content(int.Parse(node.NodeID));
    
                    if (content.ContentType.Alias == "Meeting")
                    {
                        var startDate = content.getProperty("meetingStartDate")
                            .Value.ToString();
    
                        var date = DateTime.Parse(startDate);
                        node.Text = String.Format("{0:MM/dd/yyyy} {1}",
                            date,
                            node.Text
                            );
                    }
                }
            }
        }
    }
    Posted Apr 13 2011, 02:23 PM by Steve with 1 comment(s)
    Filed under:
  • Chapters and Seasons

    As many of you know I stand firmly against the new TSA screening procedures and indeed I have been quite vocal about them. I cannot accept that men, women and children are forced to play russian roulette with their dignity and health. And I cannot accept that there is zero accountability or oversight for those making and enforcing these new policies. I do however accept that not everyone feels the same way I do. Yet for me this is a deeply personal issue and I do not want to fly while these policies are in place.

    About four months ago, before the new airport screening procedures took effect, I took on the role of Developer Evangelist at DevExpress. This position entailed, along with other things, that I would be traveling regularly to speak at events across the country and perhaps the world. I was very excited to join the DevExpress team because, quite frankly, they have the best products on the market and an even better team of passionate people standing behind them.

    Unfortunately with the new air travel procedures I am no longer able to fulfill the requirements of the Developer Evangelist role. A secondary option was presented to move to Los Angeles and be a Technical Evangelist, but I am passionately in love with the Seattle area and the new life I have been creating here. With great sadness I am no longer employed with DevExpress. I wish the team there all the best.

    What’s next for me? I have no idea. To be quite honest I’ve been running balls all for more than three years including 118 community events and Geek Road Trip and I’m starting to realize how tired I am. Exhausted. Burned out. Indeed you all were right that it is impossible to maintain this lifestyle indefinitely. So I am going to start by getting some sleep. I also decided to take a vacation right after I found myself asking if I’m allowed to take a vacation. It’s been years since I last went on vacation though and to be honest I have no idea what a vacation looks like or where I’ll go. Among the things I’d like to do though are sleep, kayak, scuba dive, hike, bike, take pictures, enjoy fine dining, experience some concerts and shows and comedy, read, perhaps dance (poorly), go to a spa, and drink some red wine. And no computers.

    As for what’s next in my career I’ve been considering a number of options:

    • Doing technical training and consulting in the Seattle area.
    • I spoke to a non-profit attorney last week about formally registering GeekGive as a 501(c)(3) and I have a few additional program ideas I’d love to see GeekGive implement.
    • I have also been considering my long-time fallback plan of being a truck driver. You all know I have gasoline running in my veins and I’m sure the conversion to diesel wouldn’t be too hard. Home on weekends, right?
    • I have a potential opportunity to get involved in a socially responsible film company.
    • I'd love to do more with my music and songwriting.
    • And finally I have been thinking about going back to school for a theology degree.

    What I do know is that I do want to spend more of my time and energy on efforts to help change the world. Indeed my heart is broken daily with truly abhorrent stories of human trafficking and fatherlessness.

    Human trafficking is now the world’s second most lucrative criminal endeavor having surpassed arms and outranked only by drugs. It is estimated that roughly 30,000,000 people worldwide are enslaved in sex and labor trafficking in 161 countries. 80% of the victims are women and girls, with roughly 1,000,000 children exploited by the sex trade. Human slavery is presently bigger than the entire 365 year trans-Atlantic slave trade (via http://slavevoyages.org/tast/assessment/estimates.faces). There is hope though. Many organizations including Not For Sale have been working tirelessly to raise awareness and engineer solutions and governments, corporations, and societies are beginning to change. We can end slavery.

    Fatherlessness is also an epidemic. It is estimated that as many as 1 in 3 children in the United States will grow up without a father. To many it may seem inconsequential, but that is far from the truth. In John Sowers’ book “Fatherless Generation” he states that “according to various sources, children from fatherless homes account for”:

    • 63 percent of youth suicides
    • 71 percent of pregnant teenagers
    • 90 percent of all homeless and runaway children (who are prime targets for human trafficking)
    • 70 percent of juveniles in state-operated institutions
    • 85 percent of all youth who exhibit behavior disorders
    • 71 percent of all high school dropouts
    • 75 percent of adolescents in chemical abuse centers
    • 85 percent of all youths sitting in prison

    “What’s more, children from fatherless homes are nearly twice as likely to struggle with hyperactivity, conduct, and emotional disorders and have a social impairment. They are nearly three times as likely to be struggling in school or to have to repeat a grade. They are five times more likely to be poor, thirty-three times more likely to be seriously abused (requiring medical attention), and seventy-three times more likely to be killed.” – Fatherless Generation by John Sowers, p 36. The facts are staggering and profound. The biggest need other than for fathers to be Dads is for men to step up and mentor fatherless kids. That can make all the difference. Donald Miller in his book "Father Fiction" says that there is something profound that happens when a child is significant in their father's life; when a father takes the time to mentor and train his son to take responsibility and be honest and treat women with respect; when a father takes the time to treat his daughter like a princess and tell her that she's beautiful and special and deserving of a good man. And he is right: the world needs more good men and women.

    Whatever the next chapters and seasons of my life looks like, I hope you all continue to be in them, and I hope to see you in Redmond soon!

  • NYC Give Camp

    Next year, January 14-16, Microsoft is helping to organize a National Day of GiveCamp. We at DevExpress are proud to have been asked to help organize a GiveCamp in New York City.

    What is Give Camp?

    Give Camp is a weekend for software developers, designers, and other technical professionals to give back to local non-profits in their community.

    More Info

    For more information, visit the Give Camp website: http://nycgivecamp.org

  • This operation requires IIS integrated pipeline mode

    I’ve been working on a few ASP.NET MVC demos recently, one of which uses a custom ActionResult to send an iCal file back to the user. As part of the custom ActionResult I add a Content-Disposition header to the reply so the user is prompted to download the file.

    When I went to test the code in the browser however (Ctrl+F5), I received a “This operation requires IIS integrated pipeline mode” exception. What makes this particularly interesting is that I am not running in IIS, but rather the out-of-the-box ASP.NET Development Server that comes with Visual Studio so I don’t have control over the “pipeline mode”. Initially searching didn’t turn up anything helpful either.

    It turns out that the answer is really quick and easy; simply change:

    response.Headers.Add(…)

    to

    response.AddHeader(…)
  • Geek Food Drive Is Back In November

    I’m excited to announce that we’re back again this year with Geek Food Drive! The challenge is simple: for every user group to hold a food drive at their November meeting this year. So many folks go hungry during the holidays, this is our chance to help some of them have a happier holiday season.

    What To Do

    Bring a non-perishable food item to your user group meeting in November and ask your user group leader to get involved.

    But That’s Not All

    We have prizes to give away as well. To start, every user group that participates will receive a voucher for five free eBooks from O’Reilly. In addition, we have prizes to give away for the groups that bring in the most items based on the following formula: Total Items Collected / Number of Attendees.

    More Info

    Check out the website for more info: http://www.GeekFoodDrive.com

    Let’s make this a great holiday season for some needy families!

  • Memo: Zune Desktop Software Usability

    I am quite disappointed at how the Zune desktop software user experience has not improved and the product groups don’t drive usability issues.

    Let me give you my experience from this afternoon:

    I have the Zune desktop software installed and I checked that it was up to date even though that option is hidden in a lot of settings and I had to guess a couple of times to find it.

    I wanted to hear a song that was stuck in my head that I knew I had downloaded from the marketplace. I had forgotten the name of the song so I typed in some lyrics. After waiting for seven seconds some results started coming back, but none of them were the right one. After the rest of the results loaded I instead opened Internet Explorer and searched for the lyrics on Bing. The Microsoft search engine knew exactly what song I was after, but the Microsoft music software does not?

    After getting the title and artist of the song I went back to the Zune desktop software, typed in the name, waiting for almost ten seconds. I had to search for it through three columns and in the “zune results” column the song name was displayed three times. Which one is it?

    The screen also displayed a “collection results” area which I guess means it is on my computer? What is a “collection”? I click on the song name to play it. I am taken to another screen that shows me all of the artists and albums I have on my computer. On the right side is the name of the song along with ‘34’. Have I played it 34 times?

    I click on the song, but nothing happens. I then double-click on the song. Within a few seconds there is an exclamation point in a yellow circle displayed next to the song. What does that mean? Then I start getting exclamation points in yellow circles next to other songs in the album and then a song I didn’t choose starts playing. If I had wanted to hear that song I would have chosen it. I click the song I want again and the yellow circles disappear and then reappear next to different songs. Are the other ones now good? I tried, but they don’t play either.

    I also notice that some songs are in there twice. I have only gotten music from the Zune marketplace so why wouldn’t it tell me that I already had the song instead of allowing me to add it again?

    I figure out that I need to hover my mouse over the yellow circle to find out what is wrong. It says “Playback error: click for more information”. I don’t understand why I got an information message to send me to another place for information. I click on the yellow circle and a box pops up saying that the Zune desktop software can’t play the song and it needs to check usage rights and to sign in. I am signed in. It is error code C00D1365. What does this scary code mean and if it needs to check usage rights then why do some songs play?

    There is a link for web help so I click that. I am taken to Internet Explorer where it tells me I need to sign in on the desktop software using the account that was used to get the music. I only have one Zune account and I am signed in. I know I am signed in because the Zune desktop software shows my name in the top right corner along with my picture and how many credits I have. Web help didn’t tell me anything new and I was taken away from the software I was trying to use.

    I then thought I might try to play the song in my playlist. I go to my playlist and click on the song, but it also now has a yellow circle. I hover over and a message again tells me to go somewhere else for information. This time I’m told that the Zune desktop software can’t play the song possibly because there is an outdated link on the Zune marketplace. What does that mean? I am now worried that the site will change a lot and I won’t be able to play my music.

    I think that maybe the software could help me since it should know both what I have and what is on the Zune marketplace, but when I right-click the song none of the options allow me to fix the problem. I try the Properties option, but nothing happens; no dialog box appears or anything. I try it again. Again nothing happens. Is the it broken?

    I finally decide I should download the song again. It has been 30 minutes so far and I was very frustrated and had almost forgotten what song I wanted to hear. I type in the title, wait a few seconds, and am again presented with the artist name three times. I click one of them and find the song. The button next to the song says download which is weird because I know I already have it. I click download and the song downloads pretty quick.

    I then go to a playlist which has the song and click it, but another song starts playing and I have a yellow circle again. I don’t understand because I had just downloaded the song again. At this point I just give up and close the Zune desktop software after about 30 minutes of craziness and having to download songs I already had and taking me to other pieces of software. I still haven’t heard my song, and I’m not sure I should buy another song that I currently like; what if the website changes again?

    The lack of attention to usability represented by these experiences blows my mind.

    * Some portions excerpted or modeled after Bill Gate’s famous leaked memo which you can read here: http://gizmodo.com/5019516/classic-clips-bill-gates-chews-out-microsoft-over-xp

    Posted Sep 19 2010, 01:08 PM by Steve with no comments
    Filed under: ,
  • I’m a Rock Star!

    Silent-NightOk, I might be exaggerating a little, no one is carrying my bags through the airport yet, but I discovered today that my very first song is available at several premiere online music services! I’m really quite excited to have it out there and see it happen!

    The song is a short one minute and forty five second instrumental piano rendition of the holiday classic Silent Night I wrote quite a few years back. Friends have enjoyed hearing it and I thought it high time to officially ‘lay it down’ as it were.

    Check it out at your favorite online music service, and just in time for the holidays: Zune, Amazon MP3, Napster. The song should be available soon on other services including: IMVU, Rhapsody, MediaNet, Thumbplay, Spotify, Shockhound, Nokia, and eMusic.

    One goofy thing though, some of the stores are listing me with another Steve Andrews. If you see two albums listed they aren’t mine, unless they are really really good of course.

    And lastly I don’t think I’ll be getting rich off the song either. Once the composer (me), performing artist (me), record company (me), and the publisher (me) get their cut, I won’t be left with anything.

  • The Power of Community

    Today is the day I finally get to announce something very exciting for me; I’ve joined DevExpress as a Developer Evangelist! I’m super excited about it! To get all the details, check out my new DevExpress blog.

  • Recursive Fields in Umbraco with XSLT

    I’ve been working with Umbraco quite a bit lately and I’m really loving it as a content management framework. I’ve already converted GeekGive.org, GeekRoadTrip.com, and I’m working on a few others. Being a developer though I often find myself outside the box and today is no different.

    I’m building a site where the homepage will actually reflect content from a subpage including the title. This means I have to get rid of my standard title block in the template and use XSLT.

    My standard title template block:

    <title><asp:placeholder runat="server"><umbraco:Item field="pageName" runat="server"></umbraco:Item> - <umbraco:Item field="siteName" recursive="true" runat="server"></umbraco:Item></asp:placeholder></title>

    I created a macro and set about to define the title text. Then it hit me, how do I recursively get the siteName field I defined on the homepage? It turns out this is really simple to do using XSLTs ancestor-or-self function in the value-of select:

    $currentPage/ancestor-or-self::node [string(data[@alias='siteName'])!=''] [1] /data[@alias='siteName']

    The full macro is:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet
        version="1.0"
        xmlns:xsl="
    http://www.w3.org/1999/XSL/Transform"
        xmlns:msxml="urn:schemas-microsoft-com:xslt"
        xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets"
        exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ">
    <xsl:output method="xml" omit-xml-declaration="yes"/>
    <xsl:param name="currentPage"/>
    <xsl:template match="/">
        <xsl:if test="$currentPage/data [@alias = 'pageTitle'] != ''">
            <xsl:value-of select="$currentPage/data [@alias = 'pageTitle']"/>
            -
        </xsl:if>
        <xsl:value-of select="$currentPage/ancestor-or-self::node [string(data[@alias='siteName'])!=''] [1] /data[@alias='siteName']" />
    </xsl:template>
    </xsl:stylesheet>

    Hope this helps!

    Posted Sep 09 2010, 05:12 AM by Steve with 3 comment(s)
    Filed under: ,
  • Code Recovery Services

    Do you have a .NET assembly that you’ve lost the source code for? Has the assembly been obfuscated thereby rendering tools like Reflector useless? I have done a few community talks entitled “May the Source Stay With You” based upon my work in code recovery and these services are available to you. If you have a .NET assembly and have lost the source code I can help. For more information, or to get a quote, contact me.

    Some things to remember:

    Proof of Ownership: You need to be able to prove that you own the intellectual property contained in the assembly.

    You can’t turn applesauce back into an apple: While you will get functional code back, it may not be exactly the same as the original code due to optimizations made by the .NET compiler and the code recovery tools.

    You retain all rights: Once the code recovery is complete you retain all rights to the source code and all files are deleted from my systems.

    Posted Aug 05 2010, 02:07 AM by Steve with 2 comment(s)
    Filed under:
  • Community Event Website Tips

    Every user group, conference, or other community event has a website. It’s a great way to provide easy accessibility to event information. Except a good number of sites don’t do that very well. I am increasing frustrated by the amount of effort required to find even the simplest detail about a user group such as a GPS-able address or contact information. Here are ten suggestions for community event websites:

    1. A GPS-able address should be on the homepage. This is especially important for speakers who may or may not be running late and desperately searching over a mobile device connection for the venue location. The address should be in plain text to enable copying on supported devices. This should also include the venue name, building name, room number, etc.
    2. The next upcoming event should be on the homepage. Nothing is more frustrating than trying to find information about an event on a site built to share information about events. The event detail should include the speaker name, date, time, and location.
    3. Provide a contact mechanism. People need to be able to contact you. Some sites list the email addresses of the user group leaders, others have a contact form. I’ve had more luck getting in touch with people directly, but the method used for contact is up to you.
    4. Have a list or previous and upcoming events. This sounds obvious to most, but there needs to be a list of events on the site. And while a calendar is nice, there should also be a list view.
    5. The official name of the group should be on every page. You may have a great acronym, but the full official name of the user group should be on every page. If it’s selectable text that’s even better.
    6. Have links to other local organizers. You should display links to other local user groups, conferences, and events.
    7. Meeting recurrence information. If your meetings are regularly occurring such as the fourth Tuesday or first Thursday (and they should be), this information should be provided on the website, and preferably on the homepage.
    8. Venue security information. If your facility has access control, any instructions should be clearly provided.
    9. Meeting schedule. If your meeting follows a specific format or flow this should be provided to the website visitor.
    10. Meeting resources. After a meeting has concluded, you should provide any resources from the meeting such as slide decks and code demos as soon as possible. This includes hosting the materials yourself, or more preferably linking the the materials on the author’s site if possible.

    What suggestions do you have?

  • Visual Studio Project and Solution Version Compatibility

    I should be able to open a Visual Studio 2008 solution in Visual Studio 2010 and still be able to open it in Visual Studio 2008 again. Currently, I cannot do incremental upgrades across a team of developers or share solutions with another developer with a newer version.

    Every release of Visual Studio I talk to countless developers who encounter this as a huge pain point in moving to the next version. And every release cycle we encounter this same problem, and every release we tell Microsoft, and every release it isn’t resolved. Microsoft is saying though that they listen to Connect votes. Today Kathleen Dollard created a Connect item for this issue, and I encourage you to vote. It’s important. It matters. And Microsoft says they take action based on Connect votes.

    Vote now: Projects and Solutions Must Be Compatible Across Adjacent Releases

    And remember, by not voting, you’re telling Microsoft this is not an important issue.

  • The Code Coverage Mirage

    In an online Q&A webcast with Scott Hanselman today the topic of Code Coverage was raised. One audience member asked what the optimal level of Code Coverage is. The answer is that there isn’t an optimal level because Code Coverage can be a misleading statistic. Take for example the following method:

    public class Math
    {
    public static int Add(int num1, int num2)
    {
    return num1 + num2;
    }
    }

    You might then write the following unit test to validate the method:

    [TestMethod]
    public void AddTest()
    {
    // ARRANGE
    var num1 = 4;
    var num2 = 8;
    var expected = 12;


    // ACT
    var actual = MathLib.Math.Add(num1, num2);


    // ASSERT
    Assert.AreEqual(expected, actual);?
    }

    This test will pass, and will also yield 100% code coverage on the Add method:

    image

    There is a crucial flaw though. What happens if you pass in int.MaxValue and int.MaxValue? To find out, let’s write another test:

    [TestMethod]
    [ExpectedException(typeof(OverflowException))]
    public void AddMaxTest()
    {
    // ARRANGE
    var num1 = int.MaxValue;
    var num2 = int.MaxValue;

    // ACT
    MathLib.Math.Add(num1, num2);
    }

    Running this test yields the following failure:

    image

    Apparently an OverFlowException wasn’t thrown after all. To understand why, let’s write one more test:

    [TestMethod]
    public void AddMaxExceptionTest()
    {
    // ARRANGE
    var num1 = int.MaxValue;
    var num2 = int.MaxValue;
    // ACT
    var actual = MathLib.Math.Add(num1, num2);
    // ASSERT
    Assert.Fail("Expected Overflow, received: " + actual);
    }

    The result is not what you might expect:

    image

    In fact, the result of adding int.MaxValue and int.MaxValue into an int yields negative two. The reason for this, to the best of my knowledge, lies in how the .NET framework processes integer arithmetic. The int type is signed, meaning the last bit of it’s 32 bits is reserved for the positive/negative flag. When it’s processed under the covers however, it’s processed as unsigned, so as it rolls up adding int.MaxValue and int.MaxValue until it flips the flag bit producing a result of negative two.

    What does this have to do with Code Coverage? Our original test adding 4 and 8 and yielding 12 covers the Add method with 100% coverage. It does not however reveal the unexpected result of adding int.MaxValue and int.MaxValue.

    Code Coverage at a low value is a good metric for finding areas of your code in need of more validation. A high Code Coverage number though means nothing without full boundary checking.

  • What is Community?

    I’ve travelled the world and the seven seas… ok, ok, just North America, but since September of 2007 I’ve had the opportunity to visit nearly 100 community events from user group meetings, code camps, micro-conferences to major tradeshows such as Tech-Ed and PDC. During my travels I’ve been able to talk one on one with numerous user group leaders and influentials and there are widely varying views as to what community is. A lot of community leaders base their metrics on how many butts in a seat they were able to achieve at their latest meeting. I’m here to tell you my friends that this is not community. Not in the slightest. It’s an association, a club.

    True community is what happens outside of organized events.

    Here are a couple thoughts:

    • How much time do you spend mentoring other developers? Jesse Riley has a great post spawned by a Jim Holmes talk on this. I’d recommend seeing Jim’s talk if you ever have the opportunity.
    • Do you invite your attendees out for food and/or adult beverages after each event? This is a great way to not only build relationships, but to find motivated up-and-coming influentials and community leaders. Less than 10% of your attendees will regularly come out afterwards, but those that do tend to have the spark and can be mentored into strong community leaders themselves
    • Is your Microsoft Developer Evangelist organizing all the events? Some of the best Developer Evangelists I’ve met rarely organize events themselves, rather they support those that are already organizing events. If folks in your local community aren’t organizing events however, that’s a great opportunity to step up and be a leader.
    • Do you make yourself available? I make it a habit to freely share my personal contact info, and unless I’m overdue on a deadline (hypothetically speaking of course), I try to make myself available. For the record:
      • Phone: (610) 883-7667
      • Email and Live Messenger: steve [at] platinumbay [dot] com
      • Twitter: SteveAndrews

    To me, community is not about a place to hang my hat and pat myself on the back. It’s a place where I can both learn and teach, mentor and be mentored, and build meaningful and lasting relationships with my peers. I’d encourage you to do the same.

    Posted Dec 24 2009, 07:00 AM by Steve with 2 comment(s)
    Filed under:
  • Tips for Releasing Sample Code

    When I’m learning a new technology, I’ll frequently download code samples that help me better understand the concepts. Often though I find myself frustrated by having to deal with formatting and extraneous information before even looking at the code. To that end I have some rules for releasing sample code.

    Format Every Document
    The keyboard shortcut for this is Ctrl+K+D. Nothing is more frustrating than looking at unformatted code.

    Code Order
    Code should be ordered in the following structure from top to bottom:

    • events
    • fields and automatic properties
    • constructors
    • abstract methods
    • methods
    • abstract properties
    • properties
    • subclasses

    Code Statements
    Include a blank line before return statements and before and after decision blocks (including using, if, switch, while). In C#, opening and closing brackets should be on their own line.

    Remove Excess Blank Lines
    There should never be more than one consecutive blank line between any lines of code. With consecutive closing brackets as well as #endregion notations in C#, there should be no blank lines between them. There should also be no blank lines between fields or at the beginning or end of method or property bodies.

    Separate Code
    There should be one blank link between properties and methods to allow the user to see logical breaks in the code.

    Code Files
    There should only be one class, interface or enumeration per file.

    XML Comments
    Always remove unnecessary XML comments from your code files. For example, this XML comment should be removed:

    /// <param name="param"></param>

    Import Namespace Placement
    Import (C#) or using (VB) directives should be placed above the namespace. Also use the Organize Usings > Remove and Sort refactoring built-in to Visual Studio 2008 and Visual Studio 2010 to remove any unnecessary directives. This also helps to make the directives more readable.

    Wrapping Lines
    Don’t manually wrap long lines of code. Visual Studio has a feature to allow a user to wrap long lines if they so choose.

    Properties
    Use automatic properties in .NET 3.0 code and above whenever possible.

    These are a few of the rules. I’ll try to keep the list updated as I run across more frustrations.

  • Visual Studio Code Formatting

    Working on a website in Visual Studio I found myself annoyed again by the extra spaces around <script /> tags when I type Ctrl+K+D (Format Code). It turns out however that this is easy to change. As with most Visual Studio customizations, the answer lies in Tools > Options.

    Under Tools > Options > Text Editor > Html > Format, click the ‘Tag Specific Options…’ button. Under ‘Client HTML Tags’ find ‘script’. Finally, under ‘Line breaks’, change the default value from “2 Before opening, within, and 2 after closing” to “Before and After”, like the Rush song.

    This isn’t specific to HTML though, most of the languages under Text Editor support formatting options. Another change I typically make is for CSS to use the Compact rules.

    Happy Formatting!

    12-20-2009 6-29-49

  • Help Rebuild New Orleans At Tech·Ed NOLA

    Just announced, registration is now open for Microsoft Tech·Ed 2010, June 7-10, in New Orleans, Louisiana. Tech·Ed isn’t the only reason you should come to New Orleans though.

    It has been four years since Hurricane Katrina devastated the gulf coast as the worst civil disaster in American history. It is estimated that 400,000 jobs were lost and 275,000 homes were destroyed, ten times as many as any other natural disaster in US history. The total cost is estimated at $100 billion in damages making Katrina the most costly hurricane in US history. Up to 15 million people were affected by Hurricane Katrina, and New Orleans itself is still struggling to rebuild and one of the biggest needs is for new housing.

    I'd like to help, so I have arranged for a volunteer group to work with Habitat for Humanity to help rebuild New Orleans on Saturday June 5th, 2010, the Saturday before Tech·Ed. This is your opportunity to help an area that still has immense need, as well as to network with fellow geeks and eat more shrimp and oyster poboys! You should try the fried alligator too.

    If you would like to volunteer to help rebuild New Orleans on Saturday, June 5th, 2010, please visit: http://geekgive.org/project/techednola2010

    For more information about working with Habitat for Humanity, please read the FAQ (Microsoft Word) and Safety Guidelines (Microsoft Word).

    I am also looking for sponsors to help with:

    • Hotel Discounts
    • Transportation
    • Breakfast
    • Lunch
    • Water
    • After-Party
    • $50 suggested donation to Habitat for Humanity per person to help cover work gloves and other costs

    If you can help sponsor this volunteer event, please contact me at steve [at] platinumbay [dot] com.

  • Serialization Generics

    I really dislike writing the same code over and over again. For my current project, this involves serialization and I ended up creating the following generic class to handle Xml serialization and thought it might be useful to someone else.

    using System.Xml.Serialization;
    
    public class SerializationHelper<T> where T : class
    {
        public string SerializeXml(T o)
        {
            var serializer = new XmlSerializer(typeof(T));
    
            var sb = new StringBuilder();
            using (var tw = new StringWriter(sb))
            {
                serializer.Serialize(tw, o);
            }
    
            return sb.ToString();
        }
    
        public T DeserializeXml(string text)
        {
            var serializer = new XmlSerializer(typeof(T));
    
            using (var tr = new StringReader(text))
            {
                return (T)serializer.Deserialize(tr);
            }
        }
    }
  • UX Fail

    I’ve been developing software for over ten years now. In those ten years software technology has grown by enormous leaps and bounds. User experience however has not. I’d argue that user experience has hardly improved at all, and I grow more and more frustrated at the wasted potential as indicated by these tweets from yesterday:

    Ok, ok, I love technology too, but mostly for it's potential. I haven't seen it live up to that yet.

    If I had to do it over, I'd be a loud and vocal critic of bad user experience. To that end, I registered uxfail.org.

    At the end of the day, most software *is* nothing more than user experience.

    I bought the domain name UXFail.org and set up BlogEngine.NET to rant, vent, and hopefully help people improve the user experience of their software solutions. Visit the site, read the posts, and feel free to submit your own fails from the battlefield.

    http://uxfail.org

    Posted Nov 30 2009, 06:23 AM by Steve with 3 comment(s)
    Filed under:
  • Shotokan Development

    Note: There is still so much more I want to say on this topic, but that will have to wait for another post as I further distill my thoughts.

    At the end of my three week stint in Redmond, WA in October and November I was thrilled to be able to support Sara Ford as she tested for her second dan (second degree black belt) in Shotokan karate. Apart from being a cold and rainy night in Bellevue, it was a utterly humbling experience. The strength, speed, focus, and control of all those who tested for 1st, 2nd, and 3rd degree black belts was amazing. More so, what I experienced that evening has really started to change the way I think about software development and community in general.

    As an aside, Sara alone was so completely focused and exhibited such speed and control that I think my eyeballs melted and are just now recovering.

    Dojos and Schools of Thought

    “A dojo (道場, dōjō) is a Japanese term which literally means "place of the way". Initially, dojos were adjunct to temples. The term can refer to a formal training place for any of the Japanese do arts but typically it is considered the formal gathering place for students of any Japanese martial arts style to conduct training, examinations and other related encounters.” – Wikipedia

    Each dojo is unique, both taking practice and methodology from those before them, and molding in their own style and techniques. More importantly though, no dojo is inherently wrong. There are no ‘my camp is better than your camp’ mantras. In the software developer community however, I find people taking sides on any number of issues: databases, version control, testing, design patterns, and even hardware. Similarly, such arguments often fail to take into account all the variables and environmental issues that must be considered to make a decision. This has long troubled me as I tend to be very pragmatic. Sure, I nag the heck out of folks on Twitter about Team Foundation Server and MSTest, but at the end of the day if they’re using a tool and TFS doesn’t solve any pain points they have with that tool then there is absolutely no reason to change. There is no one right answer. There can’t be. Life isn’t that simple.

    Philosophies and Mindsets

    "The ultimate aim of Karate lies not in victory or defeat, but in the perfection of the character of the participant." - Gichin Funakoshi (1868–1957)

    In each Shotokan dojo, the precepts are displayed on a wall somewhere. These precepts typically include seeking perfection of character, being faithful, endeavoring to excel, and respecting others.

    Similarly, I believe that the goal of practicing software development should not be producing software, but rather to continually improve and subsequently solve real business needs. The real value of software is not technical. The real value of software is to improve someone’s life. Whether that involves automating a manual accounting system, building an e-commerce website to provide online revenue, or any other countless systems that software developers build. The philosophy of software development should also not just be about the technology. It should also encompass the attitude and character of the developer.

    Senseis and Teachers

    From Japanese 先生 sensei, literally "one who lived before" - Wiktionary

    In Shotokan, the term Sensei is reserved for those who have achieved fourth dan or higher. Once achieving the sensei status, students are expected to start teaching others. It does not however mean the end of direct learning; senseis continue to be taught by those their senior. Teaching others is to be taught in return; I have been privileged to learn far more by teaching than by simply being taught.

    During the exam, I was immediately hit square in the face by the attitudes of the senseis: learning is never complete and the goal of any good teacher is to help the student improve. During the course of the exam, students were called out periodically for not having demonstrated a particular technique correctly. Many times they were made to re-do the technique solo with instruction from the senseis. Instead of ridiculing or degrading the student however, it was recognized as an important time to provide instruction to help the student become more proficient, and it was done in a loving and fatherly manner with the aim of helping the student improve, not improving the sensei’s position. In fact, it might even be considered shameful to dojo sensei in front of the guest seventh and ninth degree black belts who administered the exam. Nevertheless, the student’s success is their success.

    Unfortunately, I am seeing the opposite in software development. Mistakes or misunderstandings often seem to be used as opportunities to devalue someone and make them feel worthless, especially in non-physical environments such as Twitter and blogs. The underlying reasons for this lies in Relational Dynamics and the Lifeboat Syndrome (think high school), but that’s another topic entirely. At the end of the day though, anyone who attempts to teach or instruct without a real desire to help the student improve is not worthy the title sensei.

    Exams and Measurement

    The exams were broken up into three parts: Kihon, Kata, and Kumite. Kihon, the basics, involves demonstrating individual techniques such as kicks, punches, sweeps, strikes, blocks, and throws. Kata, or forms, is a sequence of choreographed movements sometimes up to ten minutes long that demonstrate Kihon as well as stepping, twisting, turning, dropping to the ground, and jumping. Kata is the practical application of Kihon; understanding perfection via repetition. Kumite, or fighting, is the practical application of Kihon with a real opponent through non-scripted sparring.

    In software technology, our current methods of evaluating an individual’s proficiency in a particular technology has been largely limited to Kihon. Do you know what framework class to use to send mail and the appropriate properties to set? What is the precision of a decimal? And yes, I’ve been asked both questions. The problem with solely using Kihon to test someone’s ability is that no matter how any particular test may be structured, it comes down to nothing more than rote memorization. Anyone can memorize the .NET framework’s namespaces and classes and answer multiple choice questions, but said individual may not have a clue as to how to use them appropriately or use multiple Kihons together in a Kata to form a more perfect solution.

    We as an industry need to find ways to more thoroughly evaluate an individual’s proficiency in a particular technology area or multiple technology areas. This means formulating ways to test individuals at a Kata and Kumite level. Some industries have worked to address this by adopted the idea of apprenticeship or internship.  During such a period, an individual works hands-on with a sensei who not only can evaluate the person’s Kihon, but also their Kata: reasoning, decision making, thought process, practical application, and can provide guidance to help the person improve. Finally, we need to test at the Kumite level before someone can be called a master at any particular level. Microsoft provides some of this in the form of the Masters exams, hands-on Q&A with other recognized masters. But we need a way to provide Kata and Kumite level evaluation at every level of a person’s career, not just the architect level.

    Belts and Expertise

    While the belt system varies somewhat by school, there are 6 levels of colored belts in Shotokan as a student approaches dan, the black belt. There are also ten levels of black belt. One amazing tidbit I learned about belts is that one has to wait 3-5 years before advancing to the next belt level. This could mean 50 or 60 years before reaching tenth dan, a lifetime of dedication. As Sara pointed out to me, “Karate is a way of life,” even if it means missing a Saint’s game.

    Our industry has tried to establish levels of expertise, typically using job titles such as Junior, Mid-Level, Senior, Architect. However, these title can be rather arbitrary as typically no real measure of proficiency has been evaluated other than a simple Kihon interview. As was mentioned above, we need a way to more thoroughly evaluate an individuals proficiency beyond rote memorization. This may include pair programming as part of the interview process (Kata), complex situational analysis for an optimal solution (Kumite), and test-driven technical skills analysis (Kihon/Kata).

    [Similarly, many companies fall victim to the mentality that hiring a team of yellow belt (junior) developers will have the same result as one second degree black belt (senior or architect) developer. This is just simply not the case.]

    Shotokan Development

    So what would Shotokan development look like? Hypothetically:

    First, there would be dojos: schools of similar thought, each one able to reach the same goals though maybe through differing techniques and technology.

    Second, there would be senseis who are the proven masters of their domain who would teach, encourage, and instruct their students, always in a positive manner towards the betterment of the student.

    Finally, there would be belts: skills, techniques and attitudes demonstrated using Kihon, Kata and Kumite to earn the next level.

  • NotAtPDC is back!

    It’s official, we’re back again this year. As you may recall, a bunch of tweeps got together last year to organize an online-only co-conference with PDC. The results and reaction where outstanding, and we’ve decided to do it again.

    Keep an eye on the website (http://www.NotAtPDC.com) as well as the Twitter account (@NotAtPDC) for details and info.

    Want to present? Sign up on the site with your session info.

  • Team Build Property Reference Guide

    TeamBuildPropertyTargetReferenceI’ve been working quite a bit with Team Build lately, and overriding properties is a method of customization I’ve found quite useful in certain scenarios. Along the way, I found Aaron Hallberg’s excellent Team Build 2008 Property Reference blog post, but it didn’t show me where the properties were referenced. In fact, there isn’t an easy way to determine where any particular Property is being used or set other than reading through the 1,500 lines in the Microsoft.TeamFoundation.Build.targets file. I decided to spend a few hours, read through the file myself, and compile a chart of each Property, what Target it is referenced by, and how it is referenced.

    Hopefully the chart is self-explanatory, but here’s some tips:

    • Target names are along the horizontal axis
      • Base represents the root of the Targets file where global Properties are set
    • Property names are along the vertical axis
    • Legend
      • Set: The Property is Set inside the Target. In the case of
      • Used: The Property is used inside the Target
      • Condition: The Target or a contained Task references the Property in a condition
      • Error If Exists: Team Build will throw an exception if the Property is set, or not set, under the right conditions
      • Null Error: Team Build will throw an exception if the Property is null
      • Depends On: The target has a DependsOn for the Property. The Property contains a semi-colon delimited list of Target names

    I do not claim the chart to be 100% without error, so verify before you use it. Please send any updates or corrections to me.

    As a side note, if you are working with Team Build, Aaron Hallberg’s blog is choked full of Team Build goodness.

  • Neat Visual Studio Test Options

    Digging around in Tools > Options today to find the answer to an inquiry I received, I found some stuff I didn’t know existed. If you work with Visual Studio Test Projects, you will want to know about these options. The Test Tools options are found in Tools > Options > Test Tools.

    Test Execution Options

    The original question I received was from someone asking how to reduce the number of test results that Visual Studio kept around after test runs. The answer lies in the Test Execution options under Test Result Management. There is an option there labeled “Limit number of old Test Results to.” By default, this value is set to 25. While 25 may be an ideal setting if you are running a multitude of test runs and want to compare results, for most of us this is overkill. Personally I set it to three, and that tells Visual Studio to clean up results older than three runs.

    Also take note of the checkbox below it labeled “Double-clicking a Failed or Inconclusive unit test result displays the point of failure in the test.” When you double-click on a failed or inconclusive unit test result, you will no longer be taken to a test result report. Rather, you will be taken to the line of code that failed in the test.

    image

    Test Project Options

    I have always been frustrated when test projects were created with the “About Test Projects” introduction file and the Manual Test. The next step after creation for me was always to delete these items. In digging around today, I discovered that what files are created with test projects is configurable. Under the Test Project node, you will find a two side-by-side list boxes at the bottom of the settings pane. The left side allows you to select a language-specific test project, and the right side contains checkboxes allowing you to specify which files are included by default.

    image

    Conclusion

    I’m sure you will find these tips as useful as I have, I know they’ll be making their way into my Visual Studio Tips and Tricks talk.

  • jQuery and MVC: JSON Form Submission

    In my last two posts (jQuery and MVC: JSON and Favorite Image Icons with jQuery and MVC) I covered some basics of jQuery’s AJAX functionality to improve user experience. One of the scenarios which may not seem particularly asynchronous friendly is form submission. Fortunately, jQuery provides for asynchronous post, and in JSON format too.

    The complete code to perform this is:

    $('form').submit(function(e) {
    e.preventDefault();
    $.post($(
    this).attr("action"), $(this).serialize(), function(json) {
    // handle response
    }, "json");
    });

    First, get a jQuery reference to the form element and add a submit event handler:

    $('form').submit(function(e) {

    Next, we need to cancel the form’s default behavior by using the preventDefault function:

    e.preventDefault();
    Next, and this is the cool part, we call the post method in jQuery. The post method takes four arguments: url, data, callback, and type. The first three should be familiar from the previous blog posts, but the last one is new. The type parameter specifies the type of data and accepts "xml", "html", "script", "json", "jsonp", or "text". The example above is using JSON.

    Rather than hard coding the url, it can be retrieved from the form element itself:

    $(this).attr("action")

    And rather than manually pulling form fields into the data object, as the form may change, we can call jQuery’s serialize function on the form itself:

    $(this).serialize()

    Finally, we can tie it all together with an MVC action. This example uses the Employee entity from the Northwind database. Since the identifier on the Employee entity is EmployeeID and not ID, id needs to be specified as an action parameter in order to retrieve the correct employee from the database.

    [AcceptVerbs(HttpVerbs.Post)]
    public JsonResult Edit(int id, Employee employee)
    {
    // do work
    return new JsonResult { Data = new { Success = true } };
    }

    One common scenario for this functionality is to provide asynchronous searching within a page. Even asynchronous form submits are possible with jQuery, making your arsenal that much more powerful.

    Posted Aug 31 2009, 10:33 PM by Steve with 16 comment(s)
    Filed under: , ,
  • Favorite Image Icons with jQuery and MVC

    User experience, that’s the name of the game these days. Green screens and console applications are (hopefully) becoming a thing of the past. In the web world, this means a more fluid and asynchronous experience. In my last post, I gave a quick introduction to using jQuery and MVC to perform asynchronous requests to the browser. In this post, I will expand on that topic and show how to build a favorite image icon.

    The concept is pretty simple. For example, in the Twitter web UI, an empty star image appears on the right side of a tweet if you mouse over it.If the star is clicked, the icon changes to a flashing dot, and then to a yellow star indicating that the tweet has been favorited. It’s a neat, asynchronous effect, and it’s fairly simple to achieve.

    First, we need three images. Here are the images that Twitter uses:

    Next, a CSS style is defined for the off, on, and loading states. The purpose of each style is to allow style switching to not only change the picture, but also to allow the state to be determined through the style class assigned.

    .favimgoff, .favimgon, .imgload { width: 16px; height: 16px; border: 0px; background-repeat: no-repeat; }
    .favimgoff { background-image: url(images/icon_star_empty.gif); }
    .favimgon { background-image: url(images/icon_star_full.gif); }
    .imgload { background-image: url(images/icon_throbber.gif); }

    On the MVC side, an action is needed to handle the server processing.

    public JsonResult SetOrRemoveUserFavorite(int favoriteId)
    {
    JsonResult result = new JsonResult();

    // do work here, and set SetOn to the proper state
    result.Data = new { Success = true, SetOn = true };

    return result;
    }

    Next, on the client side, add an image tag with the class attribute and id set. The image is set to a one pixel transparent gif otherwise certain browsers may not render the background image.

    <img class="favimgoff" src="<%= Url.Content("~/Content/images/spacer.gif")%>" id="1" />

    Finally, jQuery on the client side takes care of the tying it all together:

    $('.favimgoff, .favimgon').click(function() {
    var $favimg = $(this);
    if ($favimg.attr('class') != 'imgload') {
    $favimg.removeClass().addClass(
    'imgload');
    $.getJSON(
    '<%= Url.Action("SetOrRemoveUserFavorite", "Services") %>', {
    favoriteId: $favimg.attr(
    'id')
    },
    function(json) {
    if (json.Success) {
    if (json.SetOn) {
    $favimg.removeClass().addClass(
    'favimgon');
    }
    else {
    $favimg.removeClass().addClass(
    'favimgoff');
    }
    }
    else {
    alert(
    'Favorite could not be set. Please refresh the page and try again.');
    }
    });
    }
    });

    Let’s step through the jQuery script. First, define the click event handler for both classes, and get a reference to the image clicked:

    $('.favimgoff, .favimgon').click(function() {
    var $favimg = $(this);

    Next, to avoid any duplicate action taken while the process is run, make sure the image isn’t in the loading state. This is necessary because jQuery will still have an event reference to the original image even when the class changes from the original two classes of on or off.

    if ($favimg.attr('class') != 'imgload') {

    Next, remove any existing class and add the loading class so the user gets feedback that their action is being processed:

    $favimg.removeClass().addClass('imgload');

    Then, make a server call to the action defined, and pass the id of the item as a parameter to the action:

    $.getJSON('<%= Url.Action("SetOrRemoveUserFavorite", "Services") %>', {
    favoriteId: $favimg.attr(
    'id')
    },
    function(json) {
    if (json.Success) {

    Finally, based on the SetOn value returned from the server call, remove the loading class and set the appropriate class:

    if (json.SetOn) {
    $favimg.removeClass().addClass(
    'favimgon');
    }
    else {
    $favimg.removeClass().addClass(
    'favimgoff');
    }

    If by chance the server call fails and Success is false, alert the user:

    alert('Favorite could not be set. Please refresh the page and try again.');

    That’s it. Utilizing the baked-in goodness of jQuery and ASP.NET MVC, providing a rich, asynchronous user experience doesn’t have to be complex.

    Posted Aug 29 2009, 08:01 PM by Steve with 8 comment(s)
    Filed under: , ,
More Posts Next page »
Powered by Community Server (Commercial Edition), by Telligent Systems
© Platinum Bay | Some Rights Reserved Creative Commons License

Disclaimer: The information in this weblog is provided "AS IS" with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. Feel free to challenge me, disagree with me, or tell me I'm completely nuts in the comments section of each blog entry, but I reserve the right to delete any comment for any reason whatsoever (abusive, profane, rude, or annonymous comments) - so keep it polite, please.