Random Thoughts of a Scatterbrain.
 Saturday, April 26, 2008

The Sad State of Secularism

4/26/2008 4:26:01 PM (Eastern Daylight Time, UTC-04:00)

This story is kind of upsetting.

Like hundreds of young men joining the Army in recent years, Jeremy Hall professes a desire to serve his country while it fights terrorism.

Known as "the atheist guy," Hall has been called immoral, a devil worshipper and -- just as severe to some soldiers -- gay, none of which, he says, is true. Hall even drove fellow soldiers to church in Iraq and paused while they prayed before meals.

 "I was ashamed to say that I was an atheist," Hall said.

"Religion brings comfort to a lot of people," he said. "Personally, I don't want it or need it. But I'm not going to get down on anybody else for it."

I dunno...it's just kind of unnerving that in this day and age, a person should feel ashamed to be known as an atheist (especially one that is respectful of others' right to believe).  In fact, recent polls have shown that atheists are the most distrusted group in America, even below Muslims:

From a telephone sampling of more than 2,000 households, university researchers found that Americans rate atheists below Muslims, recent immigrants, gays and lesbians and other minority groups in “sharing their vision of American society.” Atheists are also the minority group most Americans are least willing to allow their children to marry.

It just doesn't make sense.

 Thursday, April 24, 2008

Automating Remote GAC Installs On Build

4/24/2008 4:42:15 PM (Eastern Daylight Time, UTC-04:00)

When working with SharePoint, you'll find yourself working with the GAC quite often during development.

If you've seen the light and you're working with SharePoint on a VM, one tricky problem is how to update the GAC using a post-build event.  The following is a little script that I use:

::----------------------- GAC binaries code ------------------------
:: Check if the share is available on the server
IF EXIST "\\server-name\temp" GOTO COPYFILES
GOTO SHOWNOTICE

:: Copy file to the server
:COPYFILES
ECHO Found \\server-name\temp; proceeding to copy files...

SET SN=\\server-name\temp

:: Copy the binary
XCOPY "$(TargetPath)" "%SN%" /Y /I

:: Use PsExec to execute gacutil
PATH=$(SolutionDir)Tools;%windir%\Microsoft.Net\Framework\v2.0.50727;%programfiles%\Microsoft SDKs\Windows\v6.0\Bin;%path%

psexec \\server-name -u Administrator -p password -w "c:\temp" gacutil.exe /i "$(TargetFileName)" /f

GOTO END

:SHOWNOTICE
ECHO Your VM image is not sharing the directory "c:\temp"
GOTO END

:END
ECHO Completed

The batch script makes use of Sysinternal's PsExec.  I've included the binary executable in my solution tree under the directory "Tools".

The script only has one assumption: the VM (or remote machine, really) is sharing the c:\temp directory (okay, and that the path to gacutil.exe has been added to the remote machine's PATH environment variable).  Here's a breakdown of the logic:

  1. The first step is to check if the directory exists and can be reached.  If not, we go to the end and show a notice about sharing the directory.
  2. If the directory is shared, the output dll from the build is copied to the shared directory using plain old XCOPY.
  3. Once it's copied over, we use PsExec to execute gacutil on the VM (or remote machine).  The -w argument specifies the working directory on the remote machine.

Enjoy!

FOR XML Needs More Love

4/24/2008 1:55:27 PM (Eastern Daylight Time, UTC-04:00)

I'm constantly amazed by the number of developers who have never worked with FOR XML EXPLICIT and the new FOR XML PATH.  If I were designing data access, it would be my go-to commands for building queries for complex data structures (nested DataReaders?  yuck!).

In the past, to support paging using FOR XML EXPLICIT queries took tons of lines to accomplish (although there is something about the whole explicitness that makes it surprisingly legible).  Now with the fancy pants ROW_NUMBER function in SQL along with CTEs, a hundred line query can be written with maybe 15-20 lines.

Here's a simple example that you can copy+paste and run:

/* 
Demonstrates usage of ROW_NUMBER and FOR XML PATH to create 
pageable XML results queries.

In this case, the key is to page only on the Route objects.
*/

--// Mock Route table
DECLARE @Route TABLE (
    Id int,
    Title varchar(100)
)

--// Mock Step table
DECLARE @Step TABLE (
    Id int,
    RouteId int,
    Title varchar(100),
    Sequence int
)

--// Insert mock data
INSERT INTO @Route VALUES (1, 'Route 1')
INSERT INTO @Route VALUES (2, 'Route 2')
INSERT INTO @Route VALUES (3, 'Route 3')
INSERT INTO @Route VALUES (4, 'Route 4')
INSERT INTO @Route VALUES (5, 'Route 5')

--// Route 1 Steps
INSERT INTO @Step VALUES (1, 1, 'Step 1.1', 1)
INSERT INTO @Step VALUES (2, 1, 'Step 1.2', 2)
INSERT INTO @Step VALUES (3, 1, 'Step 1.3', 3)
INSERT INTO @Step VALUES (4, 1, 'Step 1.4', 4)
INSERT INTO @Step VALUES (5, 1, 'Step 1.5', 5)

--// Route 2 Steps
INSERT INTO @Step VALUES (6, 2, 'Step 2.1', 1)
INSERT INTO @Step VALUES (7, 2, 'Step 2.2', 2)
INSERT INTO @Step VALUES (8, 2, 'Step 2.3', 3)

--// Route 3 Steps
INSERT INTO @Step VALUES (9, 3, 'Step 3.1', 1)

--// Route 4 Steps
INSERT INTO @Step VALUES (10, 4, 'Step 4.1', 1)

--// Route 5 Steps
INSERT INTO @Step VALUES (11, 5, 'Step 5.1', 1)
INSERT INTO @Step VALUES (12, 5, 'Step 5.2', 2)
INSERT INTO @Step VALUES (13, 5, 'Step 5.3', 3)
INSERT INTO @Step VALUES (14, 5, 'Step 5.4', 4)

/*
Define the page size.
 -- Add sorting and ordering later
*/

DECLARE @PageSize int
DECLARE @CurrentPage int

SET @CurrentPage = 0
SET @PageSize = 3

/*
Calculate starting and ending row.
*/
DECLARE @StartIndex int
DECLARE @EndIndex int

SET @StartIndex = @CurrentPage * @PageSize
SET @EndIndex = @StartIndex + @PageSize

; --// Need to terminate with a semicolon for CTE 
/*
Perform core XML select
*/

WITH Routes AS (
    SELECT 
        *,
        ROW_NUMBER() OVER (ORDER BY Id) AS 'RowNumber'
    FROM
        @Route
)
SELECT
    Routes.Id AS "@Id",
    Routes.Title AS "@Title",
    (
        SELECT
            Step.Id AS '@Id',
            Step.Title AS '@Title'
        FROM
            @Step AS Step
        WHERE
            Step.RouteId = Routes.Id
        ORDER BY 
            Step.Sequence ASC
        FOR XML PATH('Step'), TYPE            
    ) AS 'Steps'
FROM 
    Routes
WHERE
    RowNumber > @StartIndex AND RowNumber <= @EndIndex  --// BETWEEN Results in improper paging
FOR XML PATH('Route'), ROOT('Routes')

What's great about this is that if your object model is properly designed, it's just a matter of deserializing the XML (using precompiled serialization binaries, of course) to rehydrate your data model.

In this case, the output XML looks like this:

<Routes>
  <Route Id="1" Title="Route 1">
    <Steps>
      <Step Id="1" Title="Step 1.1" />
      <Step Id="2" Title="Step 1.2" />
      <Step Id="3" Title="Step 1.3" />
      <Step Id="4" Title="Step 1.4" />
      <Step Id="5" Title="Step 1.5" />
    </Steps>
  </Route>
  <Route Id="2" Title="Route 2">
    <Steps>
      <Step Id="6" Title="Step 2.1" />
      <Step Id="7" Title="Step 2.2" />
      <Step Id="8" Title="Step 2.3" />
    </Steps>
  </Route>
  <Route Id="3" Title="Route 3">
    <Steps>
      <Step Id="9" Title="Step 3.1" />
    </Steps>
  </Route>
</Routes>

Next, you'll need some simple code to deserialize the XML to make it useful:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Xml.Serialization;

namespace XmlDeserialization {
    internal class Program {
        private static void Main(string[] args) {
            string xml = ...; // XML string here

            RouteList routes = new RouteList(xml);

            Console.Out.WriteLine(routes.Count);

            foreach(Route route in routes) {
                Console.Out.WriteLine(" + Route: {0}", route.Id);

                foreach(Step step in route.Steps) {
                    Console.Out.WriteLine("   + Step: {0}", step.Id);
                }
            }
        }
    }
    
    public abstract class XmlDeserializingList<Titem> : List<Titem> {
        protected XmlDeserializingList() { }

        protected XmlDeserializingList(string xml) {
            StringReader reader = new StringReader(xml);

            XmlSerializer serializer = new XmlSerializer(GetType());
            XmlDeserializingList<Titem> items = (XmlDeserializingList<Titem>)serializer.Deserialize(reader);

            AddRange(items);
        }
    }

    [XmlRoot("Routes")]
    public class RouteList : XmlDeserializingList<Route> {
        public RouteList() {}

        public RouteList(string xml) : base(xml) {
            
        }
    }

    [Serializable]
    public class Route {
        private int id;
        private string title;
        private Collection<Step> steps;

        [XmlAttribute]
        public int Id {
            get { return id; }
            set { id = value; }
        }

        [XmlAttribute]
        public string Title {
            get { return title; }
            set { title = value; }
        }

        [XmlArray("Steps"), XmlArrayItem("Step", typeof(Step))]
        public Collection<Step> Steps {
            get { return steps; }
            set { steps = value; }
        }
    }

    [Serializable]
    public class Step {
        private int id;
        private string title;

        [XmlAttribute]
        public int Id {
            get { return id; }
            set { id = value; }
        }

        [XmlAttribute]
        public string Title {
            get { return title; }
            set { title = value; }
        }
    }
}

It might even be useful to add some abstract methods (and properties to support it) to GetNextPage()

Nuking SharePoint Styles For Layout Page Applications

4/24/2008 8:59:46 AM (Eastern Daylight Time, UTC-04:00)

SharePonit layout apps (as I call them) are the missing link in most developer's understanding of SharePoint and why it seems like it can be a pain in the butt as a development platform.  As I've discussed previously, SharePoint development only deviates from regular ASP.NET development ever so slightly.  A bit of creativity and ingenuity easily overcomes most hurdles.

As I'm doing development in the area, I'd like to help shed some light on the mystery of it all and show how developers and SharePoint can work together in harmony :-)

One of the first steps to making happy with SharePoint when working with layout pages is to nuke the SharePoint CSS which creates weird padding around the main work area.  I'm sure it may have some purpose, but it's irrelevant for us at the moment.

Let's take a look.

In the following screen, I've added a <div/> element with a one pixel, black border with width and height set to 100% (this is in IE7 and it looks about the same in FF2).

Notice the fat white padding on the top and the right.  This is useless and ugly.  Not only that, we didn't acheive the 100% height that we'd like to.  We can nuke it with some CSS:

/*--- override WSS styles ---*/
body { height: 100%; }
.ms-formareaframe { padding: 2px 4px 4px 4px; background: #fff; height:100%; }
.ms-propertysheet { height: 100%; }
#onetidMainBodyPadding { height: 0px; }
#onetidMainBodyPadding img { height: 0px; display: none; }
#onetidYPadding { width: 0px; }
#onetidYPadding img { width: 0px; display: none; }

And here's the result:

Bingo!  It looks kind of the same in FF2 (FF2 overdraws the 100% declaration and cuts off the bottom and right borders; this does require some CSS hackery to fix).

But the big picture is that now we have a blank slate with which to integrate with SharePoint.  You get all of the benefits of SharePoint authentication, document management, profiling, and so on just by putting your ASP.NET application into SharePoint as a layout page.  Development is easier than it would seem since the package, during development, only has to be deployed once.  Otherwise, all of the files can be deployed to SharePoint using an automated XCOPY or manually.  In some cases, for example working with ASPX page layout, the page can be accessed directly via file share (this is how I do all of my layout).

For more info on creating layout apps, check out the following articles on packaging SharePoint solutions:

 Tuesday, April 22, 2008

Quote of the Day

4/22/2008 11:43:04 PM (Eastern Daylight Time, UTC-04:00)

I'm not a metal fan, but I like this one.

"We Need To Let Metal And Odin Catch The Kids Before Jesus Does!" -- HELHEIM

Funny.

New Jersey Gets *Something* Right

4/22/2008 2:10:06 PM (Eastern Daylight Time, UTC-04:00)

High property taxes?  Check.  Terrible congestion?  Check.  Exit 13?  Check (for those not in the know, exit 13 on the NJ Turnpike is the location of an all encompassing foul odor from the refineries located in the area).  Overabundance of guidos?  Check.

For all the reasons that NJ sucks, there are a few bright spots like the grease trucks at Rutgers and an interesting little ruling by the NJ Supreme Court:

The justices say that IP addresses are sufficiently anonymous to justify privacy protection because, theoretically, only the Internet service provider can identify who is associated with a specific IP address.

"Internet users today enjoy relatively complete IP address anonymity when surfing the Web. Given the current state of technology, the dynamic, temporarily assigned, numerical IP address cannot be matched to an individual user without the help of an ISP. Therefore, we accept as reasonable the expectation that one's identity will not be discovered through a string of numbers left behind on a website"

 Monday, April 21, 2008

VSTO Versus Extensibility

4/21/2008 11:57:14 AM (Eastern Daylight Time, UTC-04:00)

As we're currently mulling a full transition to VS2008 and .NET 3.5, I've been investigating VSTO3 and ClickOnce once again.  My initial encounters with VSTO and ClickOnce were lacking.  With regards to VSTO, I didn't find anything that I could do with it that I couldn't do without it.  Indeed, it's more of an extension of the extensibility model which provides some under the cover plumbing than anything else.

The decision to attach ourselves to VSTO3 and ClickOnce is no light matter.  Luckily, Cindy Meister (Office MVP) and Mary Lee (Microsoft) were kind enough to weigh in on the matter over at the MSDN forums.

I think all Office developers should head over and take a look as it contains a wealth of information (and clarifies some common misunderstandings) with regards to VSTO and ClickOnce.

 Wednesday, April 16, 2008

Geek Moment

4/16/2008 9:39:38 PM (Eastern Daylight Time, UTC-04:00)

It's more rare these days, but I realized I had a total geek moment as I was walking back to my office after eating cheese and crackers for dinner because I was too busy working on reviving a 6 year old PC.

Nothing quite like a power supply sitting outside the case to let you know that you've geeked yourself out for the day.

As a side note: those Laughing Cow cheese wedges are pretty damn satisfying for 30 calories.

 Tuesday, April 15, 2008

On The Suckage Of Lotus Notes (6.5)

4/15/2008 12:49:50 PM (Eastern Daylight Time, UTC-04:00)

Lotus Notes continues to suck as much as ever.  Every day, I wake to find more suckage.

For example, today, when a coworker forwarded a meeting invitation to me, instead of allowing me to accept it in my calendar and schedule the event, it came across as a regular e-mail with no option to accept the meeting invitation which was attached.

Furthermore, there's this little gem:

Uhhh...thank you Lotus Notes for informing me that the meeting occurs in a different time zone.  It would be nice if you could tell me which time zone.  You know, since I can't automatically schedule the event, it would be nice if you could just tell me what time zone it's in so I can manually schedule it.  Furthermore, see that little outline around the globe and arrow?  This would lead one to believe that clicking on it does something like maybe map the actual time...but nope, nothing happens (the same with the text).  LotusNotes = Productivity--

Meanwhile, Amazon Prime is the polar opposite of suckage.  I ordered two books yesterday and used the default Prime "free" 2nd day shipping option.  To my surprise, they've arrived on my doorstep less than 24 hours later.  If that isn't awesome, then I don't know what is.

 Monday, April 14, 2008

Office Developers: Take Note!

4/14/2008 5:14:29 PM (Eastern Daylight Time, UTC-04:00)

Microsoft has a very powerful set of group policy administrative templates which allow administrators to set configuration options for Office globally for all users in the domain.  This makes many development scenarios much easier since it allows you to easily ensure consistency in terms of Office configuration instead of writing custom code to do it in your add-in.

You can download the templates from MSDN.

You can find more details about installing and using the templates here.

And in case you were curious, here's a screen cap:

This is a must explore set of tools when working with Office applications.

 Monday, April 07, 2008

On The Shortcomings of WF

4/7/2008 11:09:47 AM (Eastern Daylight Time, UTC-04:00)

An article in the April issue of MSDN magazine features an interview with Bjarne Stroustrup, the man that invented C++.  There's an interesting quote that quite eloquently and succintly sums up my distaste for Windows Workflow Foundation and BizTalk (at least the versions that I've worked with).

When asked about his feelings on IDEs and how they should (or should not) support languages and the role of the IDE in software development, Stroustrup responsed:

I'm not a heavy IDE user.  I appreciate a responsive IDE editor with understanding of my language, but I also want to be able to work without an IDE.  My desire for portability of code plays a role here.  With C++, I want to be able to understand my system from just the source code in the source files.  I actively dislike IDE mechanisms that involve trasformations or generation that cannot be represented as code fit for human consumption.

While WF does certainly generate code in the background, it's not what I would consider "code fit for human consumption".  It's messy and aesthetically unpleasing (so far as code goes).  I always inevitably end up spending quite a bit of time cleaning up the mess left by the code generation engine; there's an odd disconnect between the cleanly delineated visual design of the workflow and the mess of code that gets generated just for a dependency property.

 Wednesday, April 02, 2008

I Think It's Time For An Upgrade

4/2/2008 1:33:26 PM (Eastern Daylight Time, UTC-04:00)

Massive droolage:

4-2-08-nehalem.jpg

Courtesy of engadget.

SharePoint As A Development Platform

4/2/2008 9:19:53 AM (Eastern Daylight Time, UTC-04:00)

I got an email today regarding a blog post by Jeffrey Palermo on the shortcomings of SharePoint as a development platform.

Now I have to say, SharePoint is not without fault (particularly in the area of feature packaging and deployment), but Jeffrey's perceived issues with SharePoint really show either the lack of personal development experience with SharePoint or a lack of creativity on the part of the team he's working with.

Let's get one thing clear first, okay?  SharePoint is meant as an enterprise collaboration and document storage platform, first and foremost.  One must always bear this in mind with regards to any discussion on SharePoint.  Why is it so big?  Why is it clunky in some places?  Why does it have to be installed on a server OS (okay, I admit, this one is probably more about licensing and $$ than anything technical)?

It seems that Jeffrey's major beef, that it must be installed on a server OS, kills any benefits of SharePoint as a development platform immediately.  So let's tackle this one first. 

First, a disclaimer: I'm not a SharePoint guru.  I don't have 5 years of experience with SharePoint.  I'm only going on what I've learned in working with SharePoint, day in and day out, for the last year.

In our development group of 5 or so people, we've managed to develop against SharePoint quite well, despite the fact that we all run XP as our primary development environment.  How?  Virtual machines.  Of course, some would view this as a hassle, as another stumbling block or quite clumsy.  I view it otherwise as there are numerous benefits in developing against a VM server environment:

  1. Every deployment is exactly the same.  This means that server names, file structures, databases, and so on are exactly the same for every developer.  This aids -- not hinders -- the development of automated scripts and deployment utilities.  On our team, we usually synchronize images once every month or so.  What this means is that we'll take turns updating a common image and then everyone will grab a copy of said image.
  2. Virtual Machines are easy to deploy.  It's called: copy-paste!  Nothing easier when adding a new developer to your team.  Instead of configuring a whole new SharePoint environment, just have the developer copy the latest development image.  So easy, a caveman could do it.
  3. Virtual Machines can be rolled back.  Try doing that with your development environment!  If every developer had SharePoint deployed on his or her machine, a mistake (deleting/altering some core database tables or records, for example) would be devastating...it would mean at least a day of lost work time trying to rebuild the development environment.  Using virtual machines to host the server environment protects it from inadvertant dismantling.  And even if it is somehow altered for the worse, no matter, get another copy from someone else!  And of course, being able to rollback the image (provided that you created a snapshot) makes updates (for example, adding a SQL Server service pack) painless.
  4. Virtual Machines are portable.  Why does this matter?  Demos!  There's nothing more convenient than having a sales guy pack up a copy of the VM with all of the software installed and tweaked for demos.  This is a huge bonus.

Look, the suggestion of developing with SharePoint in a "native" environment in a team is just plain stupid; it's a matter of working harder, not smarter and it shows a lack of creativity in terms of development management.  (One disclaimer: some Visual Studio tools from Microsoft for SharePoint cannot be installed on XP...this is a shortcoming, for sure, but it hasn't really affected our development.  If absolutely necessary, you can install a stripped down copy of Visual Studio on the VM).

Now let's address each of the other 7 points that Jeffrey brings up:

  1. SharePoint isn't easy to install.  I'm going to skip that one because clearly, this man has never installed SharePoint.  It's nothing more than point and click...my gosh, I don't understand how it could possibly be easier.  Aside from this, using a VM approach, it only has to be installed once.
  2. SharePoint isn't easy to configure.  See above.
  3. SharePoint does not integrate well with simple tools.  I'm not sure what he means here.  Many administrative tasks can be handled by stsadm.exe which in turn, means that many of the administrative tasks can be handled by batch scripts.  Aside from this, SharePoint is just an average ASP.NET application.  Stopping and starting IIS, xcopy, and so on...these are all still applicable to a SharePoint deployment.
  4. SharePoint isn't easily extended to make simple tools.  What?  Nothing could be further from the truth.  The only beef that I would hold is that Microsoft doesn't package the SharePoint DLLs separately so you have to extract the DLLs from the GAC of your server environment.  But once you do that, it's easy to reference and use the API by copying the DLLs to your development environment.
  5. SharePoint isn't easy to debug.  Again, I'm not sure what the issue here is.  The process of debugging SharePoint applications (web parts, layout pages, etc.) is no harder than debugging any standard, run of the mill ASP.NET web applications.  Okay, sure, you can't just hit F5 (oooh, the horror!), but seriously, I hate F5 developers - sometimes, F5 just isn't the way to go, dude.  I'm also pretty sure chimps (or macros) can be trained to hook up the debugger and hit F10 and F11.  As for debugging core SharePoint, well, I guess he has a point since the source and debugging files aren't available (not that I know of), but I don't see that as an issue.  I mean, how many platforms ship with debugging symbols included?
  6. It's not easy to create test automation for SharePoint.  There is some truth to this since it requires the developer to learn about the platform first (API, database tables, web services, and so on).  But I don't think it's any more difficult or challenging than setting up automated tests against any other third party platform.
  7. SharePoint configuration does not store easily in source control.  See above regarding VMs.  Aside from this, he's got it all wrong again.  We can look at this from a few different angles.  First, SharePoint is just an ASP.NET application.  Repeat that to yourself about 100 times.  With regards to application configuration (in terms of the web.config), it's as simple as copying the web.config to your source control system and using a script to deploy it on build.  Secondly, if we look at the configuration in terms of web parts and layout pages, it's possible to include these in source control as well using solution packages deployed either on build or manually as features.  Certainly requires a bit of research to get it working the first time, but it's not a task that takes more than 1-2 days of experimentation.

From personal experience, I've found SharePoint a very compelling application development platform (again, that's not to say that it doesn't have shortcomings) because it's nothing more than ASP.NET but with the added bonus of a document management/storage API, profiling, permissions, and it acts as an integration platform for a variety of applications. 

You can make it as hard or as easy as you want it to be with regards to developing applications for SharePoint.  It's only a matter of how much time you are willing to put into flipping through the API and understanding the fundamentals of working with SharePoint.  A big part of successfully and painlessly developing against SharePoint is creativity in terms of setting up your development environment and automation (batch scripts, pre/post-build scripts).

The points that Jeffrey, didn't bring up -- the true pain points -- are really "fringe" features so far as I'm concerned.  Namely, this centers around SharePoint hosted and integrated workflows and InfoPath (because no one likes and no one actually uses the otherwise useless and purposeless InfoPath).  You're not required to use InfoPath or SharePoint hosted workflow; in FirstPoint, absent the early documentation and tools required to be productive on this front, we made an early decision to host workflow in our own environment. Sure, we miss out on some of the native features of SharePoint like workflow state visibility and integrated forms via Forms Services, but I don't see it as something we can't overcome as documentation and tool support becomes better on this front.

RSS 2.0 Atom 1.0 CDF