Archives

Archives / 2004
  • Wrapping long questions in SharePoint surveys

    Nothing like finding a solution to a problem for the end of the year. Don't say I didn't give you anything.

    I was recently asked about how to tackle long questions in surveys with SharePoint, specifically there's a problem that long questions don't wrap so you get a really ugly looking website. Go ahead, create a survey and add a really long question to it. Notice how you're stuck with horizontal bars from hell? Here's how to get rid of it.

    1. Create your survey as you normally would.
    2. Select Respond to this Survey.
    3. Click on the Edit with Microsoft Office FrontPage on the IE toolbar. This will launch FrontPage with the NewForm.aspx page loaded.
    4. Right click on the Survey form in FrontPage and select Customize SharePoint List Form from the popup menu. This will convert the form to something you can edit. NOTE: It's not pretty as all the HTML tags are now literal so be careful editing these!
    5. Scroll down and find a tag that starts with something like this:
      <Content xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">
      The rest of this tag will contain the HTML for your survey form (like I said all the HTML tags are literal so <TD> will look like &lt;TD&gt;)
    6. Find the tag that looks something like this TR&gt;&lt;TH nowrap valign=top class=&quot;ms-formlabel&quot;&gt;
    7. Change the TH nowrap to TH wrap
    8. Save the page and return to your browser.

    You'll see the change in FP and when you refresh the page in your browser. The text now wraps and all is well. Neat huh? Repeat this for each question (keep looking for the ms-formlabel class). These instructions are only for the NewForm.aspx page which is what users will see when they respond to a survey. There are still other pages which suffer from the "nowrap" tag so you'll have to edit each of those. They are:

    • DispForm.aspx (used to view a single result)
    • EditForm.aspx (when you edit an existing response)
    • summary.aspx (when you want to see a graphical view of all responses)

    AllItems.aspx and overview.aspx don't show the questions so you don't have to worry about this files.

    Another way to do this is to open up the site, not the page, in FrontPage and expand the survey you want to edit using the Folder List (Alt+F1) from the View menu. From here you can just edit NewForm.aspx and the other pages directly and take out that nasty "nowrap" attribute.

    Hope that helps and have a safe and happy New Year!

  • Quirky little things about Lists and Views

    Things always come together in two ways. A blessing and a curse. Take SharePoint lists and views for example.

    The blessing is that they're really powerful stuff where a user can define how they want to view the information in a list. Grouping, sorting, filtering, style. All great stuff.

    Now for the curse.

    Often what's displayed in a view isn't enough. Sometimes the user doesn't like the way the grouping works. The most common thing is the "Group: " tag that gets added and people want to just see the name of the group. Or maybe they want some funky javascript so that when you click on a group it expands and collapses the list (like Jim Duncan documents here). Little things that make usability a better thing.

    So here's the curse I came across that you might keep in mind. It's a great thing to save a list as a template for later use. You can even write a silly little tool like I did to generate hundreds of lists across multiple sites, all using the same template. The rub is that the template isn't forgiving.

    Case in point. I created a new list with various views that sliced and diced the data up so the user had a good set of links to quickly look at information in bundles rather than a big list of line items. The list was created and named ProjectSubmissions.

    TIP: When you create a list, view, or column it's best to name them without spaces and rename them later for display purposes. Why? If you create a list or column with the name "My List", internally SharePoint will store it as "My_0x00_List" (or something like that, it varies with the tides of the moon). When you're trying to do something programmatically with the list you'll be tearing your hair out trying to figure out the internal name. To avoid this, just name it "MyList" (no spaces) and then after it's been created go into the settings and change the name to something more visually friendly like "My Fabulous List". You'll always refer to it in code or by url as "MyList" but it makes it easier in the long run, trust me.

    Okay, so I had my list and created various views to sort/group the information. One of the fields was called "SiteType" but the user wanted a view grouped on this field but rather than seeing "SiteType: <group data>" in the grouped label, they wanted it to say "Program: <group data>" and filter the grouping so that it only showed data where SiteType = "Program" (which was a choice field). Follow me so far? Okay, easy enough. Each view is a new .aspx page that SharePoint creates for you when you build a new view so you can easily load this up into FrontPage and with a quick conversion to an XSLT view, change whatever you like. 2 minutes later the grouped view was renamed and all was well.

    Now here's the killer. After a few hours of development (Creating lists and views is so damn easy with SharePoint!) we packaged it all up for remote deployment via a tool to create hundreds of these little things. At the last minute it was decided to change the name of the list from "ProjectSubmissions" to "SiteCatalog". No problem. That's easy enough right? It was and everything seemed to work. Zoom, zip, off goes the deployment to the various sites and everything works. Until someone clicks on the one customized view when then points back to the originally named list! ARGH! For whatever reason, the internal name that was originally created in the list was saved when the view was unghosted to do that simple little edit. All the other views, even though they were generated .aspx pages worked fine. The one unghosted page though was static and thus pointed back to the originally named list "ProjectSubmissions" which now was called "SiteCatalog". Boom, 404 is your result.

    Anyways, be careful with your templates. They remember everything and don't care if you didn't.

    Other things that irk me (and are fast elevating themselves to becoming a peeve) is the fact I can't group on a calculated field. Or that I can't filter lookup fields. And why can't I export/save the contents of a list created using the Issue template like I can with every other list? And the list goes one.

    Okay, enough ranting. Hopefully Microsquishy will listen to the cries of us stonecutters and make life better in a future version of service pack. Until then, we do what we can with what's there, twiddling and changing things hoping we're not shooting ourselves in the foot while we do it.

  • Managing Virtual PC Images with SharePoint Development

    I have a lot of Virtual PC images. A lot. Like 20+ just for SharePoint development alone. It seems excessive, but there are a lot of configurations I need to suport (https vs anonymous vs workgroup) as well as various sites we host at work (several SharePoint based applications, a few portals and a couple of Enterprise portals in development for 2005/06). On top of that, I have a few setups that are the SharePoint 2003 / Visual Studio 2005 experiments (which are pretty ugly at this point). Managing all these images is a bit of an issue and even at 5-10gb per image, a 200gb drive fills up pretty quick.

    I stumbled across a nice post by Jan Tielens on Virtual PC images and differencing. Something I hadn't done before as all my images are built from scratch. This is not only time consuming in the construction (and something a trained monkey or a well-written NAnt script could do) but they're time consuming to copy around when you need something "almost" like that image but not quite. There is a nice walkthrough blog here on Matt Hausmann's site that gives you a nice visual guide on building difference images.

    So after spending a dozen hours or so butchering my SharePoint images, I've reduced my VPC files from 180gb down to 25gb with the same number of images. Pretty slick and creating a new one takes about a minute. I highly recommend you take a look at this for your own VPC image management if space or time is a concern. Now onto my Visual Studio images. Sigh.

    Okay, so this post wasn't really a HOWTO on managing Virtual PC images but hey, it's something to blog about.

  • SharePoint Code Camp

    I recently stumbled over Thom Robbins .NET Weblog (now a new place I visit on a regular basis) and found a cool idea called Code Camp! Code Camp is where you get as many developers together as you can and, well, code. It's somewhat of a new concept (new to me anyways) but really looks like it rocks and has somewhat of an open source quality to it (all code is free and openly shared with everyone). Best of all, it's FREE! The "official" Code Camps are composed of hundreds of developers and there's one coming up in February. Check out the MSDN Code Camp site for more info (although it's pretty slim on details right now). Additionally, Thom published what he calls the Code Camp Manifesto which puts together some simple protocols to follow.

    Anyways, the idea really interests me and will be a blast so I'm going to look at organizing a SharePoint Code Camp. On the off-chance I can't get enough raw SharePoint developers (which may not be surprising), I'll look at doing a more general .NET/Web Services Code Camp (perhaps talking to SharePoint, have to get it mixed in there somewhere). I'll hit up the local RD John Bristowe and my MSDN contacts to get something happening in Western Canada for the new year.

    As Code Camp content is determined by the community I'll be looking to you to contribute. So come by, learn, teach, have fun, whatever. Let me know if you're interested in attending, participating, helping, etc. and we'll see what we can shake up.

  • Consuming Web Services with SharePoint

    Merry Christmas! Hope you and yours are having a happy holidays.

    I've been working a lot with consuming web services and DataView Web Parts (DVWP) with SharePoint lately. FrontPage 2003 lets you create these very cool things called DataView Web Parts. Basically they consume a web service (either one your write or something someone can provide) and expose the results as a webpart that you can use/re-use on your SharePoint site. With the magic of XSLT you can get the results looking grand.

    This example walks you through consuming a web service from the Microsoft Money site and get live stock quotes (well, 20 minute delay anyways) all without a stitch of code. Okay, no C# written here but some people will say that coding XSLT is pretty much the same as writing code. You be the judge however the example here was to get a single stock quote web part consuming an external web service, all without having to break out your Visual Studio.NET toolkit.

    First we'll need a page to add the DVWP to. This can be your default.aspx page but I prefer to create a new webpart page, stick it into a document library and edit the page from there. That way I'm not un-ghosting my default.aspx page and I can delete the doclib later and not use it in production. Either way, your choice.

    1. Load the page up into FP2003
    2. Select (or create) a Web Part Zone
    3. Select Data | Insert Data View from the menubar
    4. Expand the XML Web Services Data Source from the Task Pane
    5. Select Add to Catalog...
    6. Enter http://office.microsoft.com/Research/Providers/MoneyCentral.asmx?WSDL the Service description location. This is the URL to the Microsoft Money Web Service.
    7. Select Connect Now. This will populate the rest of the dialog with the available services
    8. Select MoneyCentralRemoteSoap from the dropdown list
    9. Select DDSQuery from the Operation list
    10. Double click on symbol in the Parameters list
    11. Enter your stock symbol in the Value field (for this post I used Canadian Pacific Railway which is "CA:CP" but you can use any valid symbol like MSFT for Microsoft, YHOO for Yahoo, etc.)
    12. Select the checkbox so you can enter this value at runtime.
    13. Double click on language in the Parameters list
    14. Enter en-US as a value here (English/United States, you can enter other values here for other languages)
    15. Click OK

    This will add a new Data Source into your catalog called MoneyCentralRemote on office.microsoft.com. You can now drag and drop this data source onto a Web Part Zone. Once you do this your web part will look like this:

    DDSQueryResult <StockData xmlns:dt="urn:schemas-microsoft-com:datatypes"><Quotes><Quote Symbol="CA:CP"><Last dt:dt="float">40.98</Last><LastTime dt:dt="string">10:05 AM</LastTime><LastSize dt:dt="float">100.00</LastSize><Ask dt:dt="float">40.98</Ask><Bid dt:dt="float">40.90</Bid><Open dt:dt="float">41.00</Open><Close dt:dt="float">40.80</Close><High dt:dt="float">41.00</High><Low dt:dt="float">40.61</Low><Volume dt:dt="float">20,172</Volume><Change dt:dt="float">0.18</Change><PercentChange dt:dt="float">0.44</PercentChange><EPS dt:dt="float">2.87</EPS><PE dt:dt="float">14.28</PE><SharesOut dt:dt="float">100.00</SharesOut><Currency dt:dt="string">CAD</Currency><Exchange dt:dt="string">Toronto</Exchange><Type dt:dt="string">Equity</Type><CompanyName dt:dt="string"><![CDATA[CANADIAN PACIFIC]]></CompanyName></Quote></Quotes><Attributions><Timing><![CDATA[Quotes delayed at least 20 min]]></Timing><Attribution priority="1"><![CDATA[<a href="http://www.comstock-interactivedata.com"><img border="0" align="absmiddle" src="http://office.microsoft.com/Research/Images/splgo.gif" /></a> Quotes supplied by <a href="http://www.comstock-interactivedata.com">Standard & Poor's ComStock, Inc.</a>]]></Attribution><Attribution priority="1"><![CDATA[<a href="http://moneycentral.msn.com/investor/partsub/funds/mstar.asp"><img border="0" align="absmiddle" src="http://office.microsoft.com/Research/Images/mornlgo.gif" /></a> Fund data provided by <a href="http://moneycentral.msn.com/investor/partsub/funds/mstar.asp">Morningstar, Inc.</a>]]></Attribution><Attribution priority="2"><![CDATA[<a href="http://privacy.msn.com/tou">Terms of Use</a>]]></Attribution></Attributions><Warning>NoWarning</Warning></StockData>

    Now you'll want to let your users enter a stock symbol and the web part will do the lookup based on that value. Do this from inside FP2003 (I find you can't always perform a connection between a DVWP and another web part in the browser)

    1. Click on a zone and select Insert Web Part
    2. From the Task Pane select the Form Web Part and add it to the page
    3. Right click the Form Web Part in FP2003 and select Web Part Connections... from the popup menu
    4. Select Provide Form Values To in the action dropdown and click Next
    5. Select Connect to a Web Part on this page and click Next
    6. Choose the DVWP in the Target Web Part dropdown
    7. Choose Modify View Using Parameters From in the Target Action dropdown
    8. Select the column next to symbol (should be the second one) and select T1 as the dropdown value. T1 is the default name for the input field on the Form Web Part.
    9. Click Next then Finish to complete the connection

    You now have a connection from the Form Web Part to your DVWP. When a user enters a stock symbol in the Form Web Part and clicks on Go, the information is fed to the DVWP (mapping the value in T1 from the Form Web Part to the symbol parameter in the DVWP). This will re-invoke the webservice behind the DVWP with the symbol value updated and return the result.

    That's it! Live stock quotes from the Internet on your WSS/SPS site (this works with both) all without a single line of code. My XSLT knowledge is abysmal (read:none) so you'll have to bear with me on the formatting of the results here but I'm some of you are crafty enough to work with this. You'll probably want to format the XSLT so it displays something like this maybe:

    Symbol MSFT
    Last 27.01
    Change +0.04
    % Change +0.15%
    Volume 65.82 Mil
    Day's High 27.15
    Day's Low 26.83

    Or whatever works for you. Just do a match on the XML so you find the Last, Change, Volume, etc. nodes and make it pretty. (and if someone wants to email me a xsd file I'll update this post and probably learn about XSLT a little). In my effort to try to achieve this look from the XML returned from the web service, it keeps coming out the same. One big XML dump. Sigh.

    Hope that gets you started using Web Services with FP2003 and SharePoint. I'm sure you'll have other uses that make sense to you as this is just an example.

  • Corporate Branding with SPS

    I gotta love the web. Somehow, somewhere, you'll be taken to corners of the web you've never seen before and find little gems of information that otherwise you might stumble across someday if you get the right sequence of keywords pumped into Google. Thanks to Chris Johnson's blog I was pointed to 2 new documents on Corporate Branding with SPS. I've been doing a lot of customization work in SharePoint lately as we're building some apps (like a new contract management system) right into the application. Some of things we've done is pretty cool (like making it look like no matter where you are, WSS or SPS, you always see the same navigation metaphor).

    So here's two Office Development articles on branding your SPS site with some great examples and ideas (like being able to add new buttons to the action area that I didn't know before). Hope it helps you:

    Part 1, Understanding the Use of the Corporate Brand
    Part 2, How to Apply your Corporate Brand

  • Applying Permissions to Lists in Areas

    A nice feature of SharePoint Portal Server are areas. Think of an area as a mini-WSS site of it's own. You can create document libraries, custom lists, discussion threads, etc. all within an area. Items in the portal, including entire areas, have the added advantage over WSS sites of being able to use audience filtering and thereby only show content to those that it's aimed for (remember audience filtering is just what's presented, you still need to apply appropriate security to deny access to something to someone).

    Security for areas is the same as you would apply security anywhere else in SharePoint. You can add new users, change permissions, etc. (although when you select the advanced permissions for an area you get more options like being able to apply stylesheets, browsing directories, etc.) One of the issues security in an area is that if you have say several document libraries in that area, the security is the same for all libraries.

    When you select a list or document library (through the Manage Content option) in SPS, you'll see the typical interface like Change general settings, Delete this list, etc. What you won't see is the option that you see when you go into the settings in a list or library in a WSS site. Namely the Change permissions for this list option. When you apply permissions to an area (using the Manage Security option), you'll see the typical SharePoint interface to add users, etc. but no option to set permissions for a list or library. You can however still use a feature of SharePoint to apply individual permissions to a document library or list in the area, it just takes a little typing to get there.

    If you hover over the Change permissions for this list option in a WSS site, you'll see a url similar to the following:

    http://servername/sites/sitename/_layouts/1033/ShrOpt.aspx?obj={1234567A-BBBB-C999D9999999},list

    This is the page where you can set permissions for a list or document library (for document libraries, the end of the url will say ",doclib" instead of ",list"). The page exists in a virtual directory that's available to any WSS site and... portal area! This same url format can be used for an individual document library or list at the portal. You just need to know the GUID (the 1234567A number above). To find this out:

    1. Select Manage Content from there area where your document library or list lives in the portal
    2. Select the document library or list from the ones available
    3. Select Modify settings and columns for that list
    4. Take a look at the url you've gone to. You'll see listedit.aspx?List={... The numbers between the {} characters is the GUID for that list. The easiest way to get from this page to the ShrOpt page is to change the URL from this:
      http://servername/_layouts/1033/listedit.aspx?List={30BDBE4A-829A-4FD1-A237-D1D3D60EFF02}
      to this:
      http://servername/_layouts/1033/ShrOpt.aspx?obj={30BDBE4A-829A-4FD1-A237-D1D3D60EFF02},list
    5. Now you'll be at the Change Permissions: Document Library (or list) page
    6. Modify the permissions as you normally would, adding or removing users and setting up permissions.

    These permissions will only be applied to the document library and not to the entire area so you can now create read-only areas with editable lists. Enjoy!

  • Creating custom pages in SharePoint

    One of the really cool things about SharePoint is that you can create your own custom aspx pages like you would any ASP.NET application, but with a few tips you can leverage all the features of SharePoint like using web part zones and allowing customization and personalization.

    When creating a custom page be sure to inherit from WebPartPage. Here is how you get the navigation on your own page.

    1. Inherit from the WebPartPage class in your new webpage:

    <%@ Page language="C#" Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage,
    Microsoft.SharePoint,Version=11.0.0.0,
    Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>

    2. Create references to required tag libraries

    <%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    3. Apply Theme server control

    <SHAREPOINT:THEME id="Theme1" runat="server"></SHAREPOINT:THEME>

    4. Add CSS Link server control

    <SharePoint:CssLink DefaultUrl="/_layouts/1033/styles/ows.css" runat="server" ID="Csslink2" />

    5. Add client-side script links

    <script src="_layouts/1033/owsbrows.js"></script>
    <script src="_layouts/1033/ows.js"></script>

    6. Create table and add navigation server controls

    <TABLE class="ms-main" CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%" HEIGHT="100%">
    <!-- Banner -->
    <TR valign="top">
    <TD COLSPAN="3" WIDTH="100%">
    <!--Top bar-->
    <table class="ms-bannerframe" border="0" cellspacing="0"
    cellpadding="0" width="100%">
    <tr>
    <td nowrap valign="middle"><img ID="onetidHeadbnnr0"
    alt="Logo" src="/_layouts/images/logo.gif"></td>
    <td class="ms-banner" width="99%" nowrap ID="HBN100"
    valign="middle">
    <!--webbot Bot="Navigation" startspan-->
    <SharePoint:Navigation LinkBarId="1002" runat="server" ID="Navigation1" />
    </td>
    <td class="ms-banner">&nbsp;&nbsp;</td>
    <td nowrap class="ms-banner" style="PADDING-RIGHT: 7px">
    <SharePoint:PortalConnection runat="server" ID="Portalconnection1" />
    </td>
    </tr>
    </table>
    </TD>
    </TR>
    </TABLE>

    That's it! Once you've done this your page is "SharePoint" ready. You can define web part zones (using FrontPage 2003) for your web designers and developers to add new webparts to for customization and personalization. Enjoy!

  • Syncronization of Office Document Properties with WSS Document Libraries

    I've been spending a lot of time with Office and syncronizing properties with WSS document libraries I thought I would share. There are a few sources out there like the WSS FAQ section on Office Interaction but I thought I would try to get into some more detail here as there are some dos and donts and gotchas along the way.

    Concept

    When you upload a document through one of several ways, properties from the document will transfer to SharePoint fields automagically. This assumes you've actually setup the fields in WSS (only the Title property is created by default). There are four ways to upload a document to a SharePoint document library where this works:

    1. Copy and paste the document into Explorer View
    2. Drag and drop a document via a mapped drive (Windows XP only) or through your Network Places folder
    3. Save the document directly from Word/PPT/Excel into a WSS document library.
    4. Upload multiple files via the Office 2003 capability

    The last two options require Office 2003 (although you can save from Office 2000 and XP it doesn't always work properly as WebDAV is a little kludgy)

    Uploading the document through the "Upload Document" option on the toolbar for the document library is a Upload->Set Properties excercise. In other words, you have to upload the document (by picking it via the Browse button) then set the properties. When you select a file from your system to upload, the properties are not automatically set (although I feel they should be so hopefully we'll see this in a future version or service pack). Using the "Upload Multiple Files" gets around this problem, but again requires an Office 2003 client.

    Built-in Properties

    Word, Office, Powerpoint and Excel (and maybe OneNote and the other "core" products) have a set of default file properties. You can set these programatically (through COM automation) or via the File | Properties menu. These properties are:

    • Subject
    • Author
    • Manager
    • Company
    • Category
    • Keywords
    • Comments
    • Hyperlink base

    These properties do not transfer to a SharePoint document library (again, I think a failing of WSS and should be fixed).

    Note: There is something deep in the central administration screens that talk about mapping Office DAV properties so I'm still looking into how this works and maybe to overcome this problem.

    Custom Properties - Microsoft

    In addition to the built-in properties, Microsoft creates by default a series of custom properties. These are accessible via the File | Properties menu on the Custom tab. By default they're all blank but you can choose to set any of them. These are named:

    • Checked By
    • Client
    • Date completed
    • Department
    • Destination
    • Disposition
    • Division
    • Document Number
    • Editor
    • Forward To
    • Group
    • Language
    • Mailstop
    • Matter
    • Office
    • Owner
    • Project
    • Publisher
    • Purpose
    • Received from
    • Recorded by
    • Recorded date
    • Reference
    • Source
    • Status
    • Telephone number
    • Typist

    Creating a field in the WSS document library with the same name as these will result in a transfer (if the property is set in the document and you use one of the four ways to upload the document). Note that once you create a field, it has an internal name (like Status) but you can change it after the fact. It will always have that internal name and if that name maps to a property, it stays that way no matter what name you change it to.

    Custom Properties - Yours

    Just like the default custom properties that Microsoft creates, there's no stopping you from adding any custom property. Just type in the name in the File | Properties custom tab and click Add. This will add a new property like "Creator" or something. You'll still have to set this but if you do, it will transfer to WSS (again if you create the field in the document library to match).

    Transfering

    As mentioned in this blog, properties set in Office documents will transfer to a WSS document library as long as two conditions are met:

    1. The property is set in the document itself as a text custom property
    2. The field is created in the WSS document library as a text field

    Custom Properties - Lookups

    One of the nice things about having meta-data for your documents in WSS is that you can control the properties and lookup values. Lookup tables are great for this but there's a problem with properties and transfering using a lookup. It doesn't work. Say you have a field called "Status" (one of the default custom properties) and set it "Draft" in the document. Status is a lookup into another SharePoint list you created where the user can set the value. When you transfer the document to WSS, the property doesn't get set.

    However if your "Status" field in WSS is a choice field with the values you want AND you have the document property set to something that matches, the transfer works correctly. WSS doesn't care you have a custom property called "Status" in your document with a value of "Fixed" but the choices in WSS are only "Draft" and "Final". It will gleefully set the value to "Fixed" but when you edit the properties, since WSS can't find "Fixed" in the list of choices, it'll revert back to nothing (or the default value if this is a mandatory field).

    So basically, if you want to have a picklist for your lookups and syncronize those values from Office -> WSS and back again:

    1. Ensure the WSS field type is "Choice" with a set of values (multi-choice through checkboxes does not syncronize)
    2. Ensure the property in Office is a text value and matches one of the choices in the WSS document library

    Value Types

    Office documents let you create 4 different value types for custom properties. Synchronziation (and the field type) in WSS must be text only and the type in the office document must be the same so store all custom properties in your office documents as Text fields in order to ensure synchronization.

    Syncronization

    As for keeping things in sync, if you set the property in WSS it will transfer to the document so when you open it and look at the File | Properties | Custom tab they'll be updated. If you set it in the document it will tranfser using one of the four methods described above. If you save a single document directly into the document library, it will clear out the file property and ask you for the value.

    Summary

    In conclusion, it's a powerful feature to synchronize (and populate) SharePoint document libraries with properties from Office documents. Imagine if you had a document library with all kinds of views using meta-data and you had a massive amount of documents with these properties set. A simple drag-n-drop operation into your document library and now all your views are ready to go. Even with issues around syncronization and non-existent built-in properties, it's a useful feature to leverage in your solutions.

    Other References

    WSS FAQ - Interaction with Office
    WSS FAQ - Syncronization Issues with Certain Properties

  • Removing Large Document Libraries

    Haven't been blogging much as I've been burning the candle at both ends (and sometimes all three ends) trying to get wrapped up for 2004 and ready for 2005 at work (not an easy task). I did have a tip that I came across though that I thought I would share.

    If you have a very large document library or list (either one with a lot of folders/documents or one with very large documents) you may find if you try to go and delete the library/list from the settings page that it fails (with a very cryptic message to contact your server administrator). The easy solution is to jump into Explorer view (yes, I hate it as much as you do) and delete files and folders from there, not grabbing too many at once. Basically I found that deleting 30 or 40 folders/files at once to be a good number. Sure, it can take awhile and you can experiment on increasing that number but I suggest you don't try selecting all 1000 files at once and deleting them. If you don't have Explorer View (personally I delete them on all my document library until Microsoft fixes the version bug with them) then just use your Network Places (or a mapped drive under XP) to get to the site and delete from there. For some reason when you delete the entire library from the admin screen, it sometimes chokes so this is a way around it. Your mileage may vary.

  • Your very own Quick Launch

    A question that gets asked often is about the Quick Launch menu in WSS sites. Whenever you create a list or document library, one of the options is to show it on the Quick Launch. This places it into a grouped category under Documents, Pictures, Lists, etc. It's very effective for directing your users to the content of the site. There are however sometimes where you want to control what you display here and in some cases, users get confused over seeing a heading called Surveys but none to be found. A simple fix is to load the page up in FrontPage and remove those sections. However here's a tip that makes it more flexible (yes, you'll still need to do this in FrontPage but only once).

    The whole Quick Launch area is just a simple table made up of Navigation webbots and headings. Rather than having tables for our Quick Launch let's replace it with a new Web Part Zone. This way we can allow web developers (and/or people with the appropriate rights) to add web parts to this section rather than having them load up FrontPage to do any customization.

    The table in question starts at line 118 of default.aspx. You can select it in design mode and either delete it or just clear out the contents (I suggest highlighting the contents and deleting it, leaving an empty table).

    So this gobbly-gook:

    <TD class="ms-navheader"><A HREF="_layouts/1033/viewlsts.aspx?BaseType=1">
      Documents</A></TD></TR>
        <TR><TD style="height: 6px">
      <!--webbot bot="Navigation" S-Btn-Nobr="FALSE" S-Type="sequence" S-Rendering="html" S-Orientation="Vertical" B-Include-Home="FALSE" B-Include-Up="FALSE" U-Page="sid:1004" S-Bar-Pfx="<table border=0 cellpadding=4 cellspacing=0>" S-Bar-Sfx="</table>" S-Btn-Nml="<tr><td><table border=0 cellpadding=0 cellspacing=0><tr><td><img src='_layouts/images/blank.gif' ID='100' alt='Icon' border=0>&amp;nbsp;</td><td valign=top><a ID=onetleftnavbar#LABEL_ID# href='#URL#'>#LABEL#</td></tr></table></td></tr>" S-Target TAG="BODY" --></TD></TR>
        <TR><TD class="ms-navheader"><A HREF="_layouts/1033/viewlsts.aspx?BaseType=1&ListTemplate=109">
      Pictures</A></TD></TR>
        <TR><TD style="height: 6px">
      <!--webbot bot="Navigation" S-Btn-Nobr="FALSE" S-Type="sequence" S-Rendering="html" S-Orientation="Vertical" B-Include-Home="FALSE" B-Include-Up="FALSE" U-Page="sid:1005" S-Bar-Pfx="<table border=0 cellpadding=4 cellspacing=0>" S-Bar-Sfx="</table>" S-Btn-Nml="<tr><td><table border=0 cellpadding=0 cellspacing=0><tr><td><img src='_layouts/images/blank.gif' ID='100' alt='Icon' border=0>&amp;nbsp;</td><td valign=top><a ID=onetleftnavbar#LABEL_ID# href='#URL#'>#LABEL#</td></tr></table></td></tr>" S-Target TAG="BODY" --></TD></TR>
        <TR><TD class="ms-navheader"><A HREF="_layouts/1033/viewlsts.aspx?BaseType=0">
      Lists</A></TD></TR>
        <TR><TD style="height: 6px">
      <!--webbot bot="Navigation" S-Btn-Nobr="FALSE" S-Type="sequence" S-Rendering="html" S-Orientation="Vertical" B-Include-Home="FALSE" B-Include-Up="FALSE" U-Page="sid:1003" S-Bar-Pfx="<table border=0 cellpadding=4 cellspacing=0>" S-Bar-Sfx="</table>" S-Btn-Nml="<tr><td><table border=0 cellpadding=0 cellspacing=0><tr><td><img src='_layouts/images/blank.gif' ID='100' alt='Icon' border=0>&amp;nbsp;</td><td valign=top><a ID=onetleftnavbar#LABEL_ID# href='#URL#'>#LABEL#</td></tr></table></td></tr>" S-Target TAG="BODY" --></TD></TR>
        <TR><TD class="ms-navheader"><A HREF="_layouts/1033/viewlsts.aspx?BaseType=3">
      Discussions</A></TD></TR>
        <TR><TD style="height: 6px">
      <!--webbot bot="Navigation" S-Btn-Nobr="FALSE" S-Type="sequence" S-Rendering="html" S-Orientation="Vertical" B-Include-Home="FALSE" B-Include-Up="FALSE" U-Page="sid:1006" S-Bar-Pfx="<table border=0 cellpadding=4 cellspacing=0>" S-Bar-Sfx="</table>" S-Btn-Nml="<tr><td><table border=0 cellpadding=0 cellspacing=0><tr><td><img src='_layouts/images/blank.gif' ID='100' alt='Icon' border=0>&amp;nbsp;</td><td valign=top><a ID=onetleftnavbar#LABEL_ID# href='#URL#'>#LABEL#</td></tr></table></td></tr>" S-Target TAG="BODY" --></TD></TR>
        <TR><TD class="ms-navheader"><A HREF="_layouts/1033/viewlsts.aspx?BaseType=4">
      Surveys</A></TD></TR>
        <TR><TD style="height: 6px">
      <!--webbot bot="Navigation" S-Btn-Nobr="FALSE" S-Type="sequence" S-Rendering="html" S-Orientation="Vertical" B-Include-Home="FALSE" B-Include-Up="FALSE" U-Page="sid:1007" S-Bar-Pfx="<table border=0 cellpadding=4 cellspacing=0>" S-Bar-Sfx="</table>" S-Btn-Nml="<tr><td><table border=0 cellpadding=0 cellspacing=0><tr><td><img src='_layouts/images/blank.gif' ID='100' alt='Icon' border=0>&amp;nbsp;</td><td valign=top><a ID=onetleftnavbar#LABEL_ID# href='#URL#'>#LABEL#</td></tr></table></td></tr>" S-Target TAG="BODY" --></TD></TR>
           <TR><TD style="padding-left:0px;padding-right:0px"><img width=1px src='/_layouts/images/blank.gif' ID='100' alt='Icon' border=0></TD>

    Becomes this:

    <TD class="ms-navheader">&nbsp;</TD></TR>
        <TR><TD style="height: 6px">&nbsp;</TD></TR>
        <TR><TD class="ms-navheader">&nbsp;</TD></TR>
        <TR><TD style="height: 6px">&nbsp;</TD></TR>
        <TR><TD class="ms-navheader">&nbsp;</TD></TR>
        <TR><TD style="height: 6px">&nbsp;</TD></TR>
        <TR><TD class="ms-navheader">&nbsp;</TD></TR>
        <TR><TD style="height: 6px">&nbsp;</TD></TR>
        <TR><TD class="ms-navheader">&nbsp;</TD></TR>
        <TR><TD style="height: 6px">&nbsp;</TD>

    Optionally you can delete all the rows (the <TR> tags) and just have one row. Now place your mouse cursor where the empty table is and select Data | Insert Web Part Zone from the FrontPage menu. This creates a new zone where the menu was:

    <WebPartPages:WebPartZone id="{8D0A3551-0BFE-4AEA-B16E-C70539440704}" runat="server" title="Zone 1">
    </WebPartPages:WebPartZone>

    Double click on the zone in design view and change the name to something meaningful (like "Menu"). Save the page and you're good to go. Now your web designers don't have to fire up FrontPage to change your system and you can drop any web part into that area.

    Additional things you can do when you're in FrontPage:

    • Set the style of the <TD> tags to ms-bodyareaframe so any web parts you drop in here look like the rest of the page
    • Remove the "Quick Launch" image
    • Change the style of the surrounding table from ms-navframe to ms-bodyareaframe (or remove the style completely) so it doesn't stand out from the rest of the page.

    Now what can you put in this new zone? Plenty.

    You could create a custom list to hold menu links, adding columns to the list for visibility (like a checkbox called Published or Visible) then create a view that filters on that. Anytime you want to add a new menu item it's as easy as adding it a new item to the list (or changing a property of a previous one to make it appear in the view).

    There are also some great treeview web parts out there (CorasWorks has one that gives you a heirachial tree view of the entire site and there are other freebies that show you an explorer like view of your document libraries). Look around and you'll find some great stuff.

    You can also save this site as a template to recreate it easily or even replace the default.aspx page on the server so any new team sites are created with this capability. Lots of possiblities here so use your imagination.

    Additional links:

    Ian Morrish has a great article on creating a dynamic menu using Web Part Pages that exist in a document library.
    Jim Duncan has a blog on how to use a XSLT Data View and grouping to create a custom expand/collapse behavior with lists. Combine this with Ian's menu and you'll have a slick UI that's all data driven from your site.

    Have fun!

  • Access denied to your own ASP.NET application

    Every have a bad day with your ASP.NET app? Ever get the yellow screen of death with this on it:

    Access to the path "C:\WINNT\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files\myapp\5607edd7\fc4d1071\hash.web" is denied.

    If you go googling for the problem, you'll find a few suggestions, solutions, ideas, and rants. We had the same problem happen at our shop a few times in the same week. In fact, it got to the point where we (the users in the local Administrator group) couldn't even access the folders themselves.

    After putting our proverbial minds to work, we did something fairly simple. We reclaimed ownership of the folders. You can do this in the security tab of the ASP.NET Temporary files directory.

    1. Right click and select "Properties"
    2. Select the "Security" tab
    3. Click on the "Advanced" button
    4. Select the "Owner" tab
    5. Select the owner (MACHINENAME\Administrators), check the "Replace owner on subcontainers and objects" and click OK

    Voila. Problem gone. App working again. Everyone is happy.

  • Folder taxonomy and path limitations in WSS

    There's a path limitation in WSS so when you have a document library with versioning turned on, at some point previous versions of a document will vanish into the ethers of SharePoint. It only happens with past versions so your current version is fine no matter how long the path is. To test this out:

    1. Create a document library in a WSS site and enable versioning
    2. Start creating folders inside of folders inside of folders
    3. Upload a document and do a quick check out/check in to create 2 versions
    4. Select the version history for that document and view version 1 of the document
    5. You should get a HTTP 400 Error - Bad Request (if not, create some more folders in folders and try again)

    I don't know specifically where the cutoff is but in testing (and from logic) my gut would say after 255 characters which is a typical limit (it's the PATH limit in Windows) and would make sense.

    So basically the rule here is to try to stay away from a folder taxonomy to organize information. META data and custom views in document libraries is so powerful as you can have everything living in one "folder" but viewed by category (or whatever makes sense for your organization). It's a hard shift from the file centric way of thinking but you can seed the troops with some tools to get them started, spend some time training them and showing them how a slice through their data is much more informative than the "where did I put that file" approach they currently use. It's a tough sell and you'll get a lot of resistance as people are comfortable with a structured file system to do their organizing for them. In the end there are a lot of benefits to viewing your information with a slightly different twist and you'll avoid problems like the one I described above (although your mileage may vary).

  • Creating a Tabbed Interface for your WSS site

    This was asked in the newsgroups about how to build a tabbed UI in a WSS site. Luckily, there's a great FrontPage component you can use for this that makes building it a breeze. First pick a site you want to add the interface to (or create a new one, doesn't matter). Next open up the default.aspx page in FrontPage 2003.

    Adding the Tabs

    The FrontPage component we want to use is the Interactive Button. Find a place on your page you want the tabs to appear. In this demo we'll put them under the site description. Once you have a place for it and the cursor positioned there, select Insert | Interactive Button from the menu. This will bring up a dialog box to describe the button. Pick a button that works with the design of your site. NOTE: the buttons don't follow the style of your WSS site so you should land on what theme you use up front before adding the tabs. Below I've picked "Soft Tab 6" which matches the default WSS site style pretty closely.

    On the Font and Image properties you can alter the button to your hearts content. Click OK to insert the button onto your page. You should now have something like this in FrontPage:

    Now select the button on the page and copy it then paste it next to each other as many times as you want a tab for (1 tab for each page). In the example below we're going to have 4 tabs going to 4 different pages.

    Each tab (interative button in FP terms) represents a different page in the site. So first save the default.aspx page 3 more times as Tab1.aspx, Tab2.aspx, and Tab3.aspx (or whatever names you want). The reason why we save default.aspx is because we want to preserve all of the parts of the page. We could have created 3 Web Part Pages to hold content, but we would lose the Quick Launch bar and other properties so this just keeps things more consistent. Also you can't copy'n'paste an ASPX page in the folder view so this works for us.

    Now load each page up by double clicking on it in the Folder List, select each button on each page and change the properties so that a) the Text property of the button is what you want it to be and b) the Link property points to the file you want the button to take you to. We'll call our tabs Home, Contacts, Tasks, and Documents. After creating the new pages with all the renamed buttons we should have something like this (4 tabs with 4 pages loaded up):

    The FrontPage work is done so save all the files and close FP down. Now go back to the site in your browser and select each tab. This will take you to each new page you created (you can check it in the Url). Now drag and drop whatever web parts onto that page that's appropriate for your design. When your users hit the site, they'll click on each tab which will take them to the new ASPX page which contains the new lists. Because we copied the default.aspx page as our original, all the great stuff like the Quick Launch bar is there (and will be updated on all pages when you add new lists) and the tab interface looks seamless! Here's our Task and Document pages showing this off:

    Additional things you can do if you want:

    • Change the style of the button for the page that's currently selected (so Home for default.aspx) so people know what tab/page they're on
    • Rather than making the content static, you can drop it onto a webpart and reuse it (haven't tried this but it should work)
    • Create your own style that will change with the style of the website (this involves editing the HTML of the link buttons to make them use the named CSS styles of the WSS site)
    • Create some more images as a border to display below the tabs to make them integrate to the site a little better
    • Change the title of each tab page (in FP2003)

    One note, the technique here of creating all new pages and saving it will end up creating a lot of duplicate buttons. You can take the extra time to go into the HTML code of the page and have the buttons point to the already existing button images rather than creating new ones each time the page is saved.

    Additional Links
    Microsoft Office Assistance - Using Interactive Buttons

  • Coming soon to a user group near you... me!

    I just got word that I'm now officially a member of the MSDN Canada Speakers Bureau. The Speakers Bureau is a collection of top Canadian speakers who are dedicated to delivering high quality presentation and demonstrations at MSDN events and at MSDN User Groups across Canada.

    I had been accepted into the group a few weeks ago, but the machinations of the internal workings at Microsoft have finally grinded to a halt and settled now. I'm very happy to be inducted into the group which includes some people I've enjoyed listening to and have looked up to like Ryan Storgaard, Kate Gregory, and my fellow Calgary MVPer John Bristowe. I look forward to participating in the group in the coming year (and what's left of 2004) and getting out to User Groups across Canada to spread the good word (whatever that word is).

    For more information on the Speakers Bureau, you can check out the link here. For a list of MSDN Canadian User Groups check out this link. Speaking of MSDN events, check out the Deep Dive on building connected systems. Each participant will get a free copy of the new Microsoft book, Enterprise Integrated Systems. Oh, come on now, you're all a flutter right? Check out the event link here for more info.

    Anyways, just wanted to toot my own horn here (although I need to get them to update my profile because when I wrote it, I didn't think it was going to be used verbatim on the site and it's a very "I'm this" and "I'm that" blather) so see you on the circuit!

  • Differences with SharePoint View Styles

    I was putting together a sampling of views to demonstrate the various view styles in SharePoint and came across a bit of a bug (well, an annoyance really). First just a quick rundown of the various styles you can apply in a view:

    View Style is the style you set by selecting it from a list when you create or edit a view. There are 7 styles to choose from, all with different twists to how they present your list or document library. The nice thing is you can get some variations on presenting things to the user without having to resort to a DVWP. Okay, I'll admit there's not a lot of styles out-of-the-box nor are they fabulous in any way. A little variety but definately not a replacement for a custom FrontPage job.

    So, without further adieu, here they are:

    Basic Table
    The Basic Table is pretty much like the Default style. See below for details on what's different but pretty much it renders your view in the typical SharePoint view. Columns with clickable (sortable) headers, etc.

    Document Details
    The Document Details style is probably the most adventurous of the bunch and renders your items 2 across (no matter how wide the page is) with each item in a box. A link to the item itself and whatever columns you enable for the view along with an icon for the item and an icon for editing it.

    Newsletter
    I couldn't quite figure out the Newsletter style at first but the only difference I found from the Basic Table or Default style is that regular text fields were bold. I still don't know why they called it Newsletter?

    Newsetter, no lines
    Same as the Newsletter style but guess what, the lines between each row have been removed. Otherwise identical.

    Shaded
    Shaded is like the Default style but every other row is shaded using the colour of the site, alternating between dark and light. Typical ledger type display and helps break up the monotony when you have a lot of items.

    Custom
    The Custom style is set when you change any of the other styles like doing grouping, totaling or even adding columns. I guess it's there to just indicate that it's not stock.

    Default
    The default is well, the default. When you create a new document library or list you get a view called All Documents (or All Items for lists). This view uses the default style.

    Now when you actually build a view and apply the Basic Table style you'll notice something. It looks exactly the same. Well it is, almost. The two are the same (ignoring the Guids for the views when compared side-by-side) however the Default style throws two copies of this snippet of code in:

    <SCRIPT LANGUAGE="VBSCRIPT">
        On Error Resume Next
         Set NewDocumentButton = CreateObject("SharePoint.OpenDocuments.2")
         If (IsObject(NewDocumentButton)) Then
             fNewDoc2 = true
         Else
             Set NewDocumentButton = CreateObject("SharePoint.OpenDocuments.1")
         End If
        fNewDoc = IsObject(NewDocumentButton)
    </SCRIPT>

    This VBScript is for rendering the correct button on a toolbar. The Default style puts the code in twice but the Basic Table only puts it in once. No biggie and it's not needed so I would classify it as a bug, but maybe I'm just difficult that way.

    Anyways, hope that explains some things about the views and what the differences (and similarities) are.

  • DataGrids, Custom columns and Paging

    I had a co-worker who presented a problem today. It was around adding paging to a datagrid (grrr Microsoft for making us do all the work!) and the fact that he had added what looked right, but the grid wasn't rendering on the page change. I went through the typical scenario of setting up paging by adding the Page Index Change event handler then, nothing. Something wasn't right and I surmised that the problem was that he had gone through a few iterations of getting the paging going and taking various approaches (hand coding the event handler, adding it to the web.config, etc.) so my conclusion was that the DataGrid, the code behind, and the aspx page were out of whack somehow. I wasn't happy suggesting the "black magic" approach to rebuilding the DataGrid with a duplicate one on the page (or creating it from scratch again) just because there had to be an easier solution.

    Tonight I built a small spike project to test out what was happening. A couple of people have experienced pain and suffering in the past with the DataGrid and how events would just vanish and not fire. One thing I noted in his code was that he had a DataGrid on the page but was then building columns on the fly (to do some custom work with the columns and linking them to subsequent pages). Once I had my spike project up and running, I turned off the auto-generated columns and fed it the datasource (a quick object with a few public properties). Everything was still fine. The problem arose when I added this:

    BoundColumn datagridcol = new BoundColumn();
    datagridcol.HeaderText = "ID";
    datagridcol.DataField = "Id";
    DataGrid1.Columns.Add(datagridcol);

    I've used this method before but usually when I created a DataGrid completely from scratch and added it to the page controls manually. In my spike project after adding this code, the DataGrid vanished completely. So the question here is this a supported design? Building columns on the fly with a DataGrid control already on the page? Or is this a hybrid that isn't supported (or recommended)? Another interesting thing to note. I now can't get to my event handlers in the Property tab in Visual Studio anymore. The lightning bolt just isn't there now. Hmmm.

    Update:
    I did find a bit of a solution. I added the following to the DataGrid in the aspx page to fix it:

    <Columns>
    <asp:BoundColumn Visible=False></asp:BoundColumn>
    </Columns>

    Now the paging works and everything shows up.

  • Using localhost for organizing your work

    I'm just wondering what people are doing to keep track of their work these days. Sure, Outlook has a good set of tools for this. Calendar, Task list, etc. but information is still disparate and I'm jumping all over the place each time I do something. Doing web development means that we have IIS (or Apache if that's your thing) at our disposal which can serve up your own local work center. With .NET installed, the possibilities are even more plentiful. So rather than having Yahoo or MSN set as my homepage I would use http://localhost and put my collection of links, tasks, documents and other useful tidbits there in some kind of organized fashion. Each time I fired up my browser I could track what I was doing or have a categorized view of resources that I use on a regular basis. I found it was somewhat more effective than using static IE bookmarks and saw it as a next generation PIM, as those have all but vanished from the desktop.

    I've grown a little dissatisfied with having a static webpage that I was constantly editing so I looked for an alternative. SharePoint, while having a good collection of features for this, was out becuase it meant I had to run it on my server and I wanted something local (and simpler). After poking around on the web, I thought the current version of DotNetNuke would be a good choice. It's been kicking around for quite sometime, was built on .NET (grown up from the IBuySpy Portal Starter Kit that Microsoft created to show people what was possible with .NET) and the latest version is pretty slick. Lots of free add-ons, private assemblies mean I just upload a zip file and it's available as a new module so no messing with compiling or messy configurations and I can make the content as dynamic as I want it to be. I've been using that for a few days now and it's pretty darn effective. I use it for tracking a list of ongoing projects and tasks, a large collection of categorized links, a document manager, a photo album and there's even an MP3 player,.all organized on tabs (with my main page calling up the Daily Dilbert as you just can't live without that). So it's been my central core for my day to day work.

    While I'm not an organization freak (my cluttered office is painful evidence of that) I'm just wondering if anyone else is using something like this and if so, what's their experiences been?

  • Writing SharePoint Web Parts, the painful adventure...

    Writing Web Parts for SharePoint is an adventure. The type of adventure that you find yourself in the middle of, realize that you don't have your fedora cap and whip, and the boulder starts rushing towards you and the spiders are crawling all over you with no exit in sight. Not a very pleasant experience for anyone.

    Luckily there are some saviors to this story. I've blogged about this before but after a weekend of writing custom web parts the painful way, I've basically given up on the Microsoft way for now and focused on using an alternative. Until VS 2005 comes along, where writing Web Parts is much easier, there is an interim solution. Fons Sonnemans and Jan Tielens got together and put together SmartPart. It's a great little addition to your SharePoint development toolbox and one everyone should have. Don't bother writing Web Parts and going through the 42 steps that Microsoft wants you to in order to get your web part created (although the Web Part Templates does make this easier). Just create a custom user control and drop it into a folder on your SharePoint server. SmartPart will happily render it for you, taking care of all the SharePoint stuff for you. The best part of this (besides not having to jump through hoops built Web Parts) is the fact that you can use the full UI design mode tools in Visual Studio to build your controls. No more RenderWebPart calls with hand building controls. Since your control is running on the SharePoint server, you can easily interface with the object model and do whatever you normally would do like accessing lists and sites and users oh my.

    Anyways, check out the GotDotNet workspace here and give it a whirl. Beats the heck out of the fugly way of doing it today.

  • Web Parts without SharePoint, ASP.NET 2.0

    I've been watching the classes in ASP.NET 2.0 for quite some time and working with the betas to see how we might build applications today so we're positioned for the changes next year (check out the Visual Studio 2005 Beta Documentation site here for all the gory details on the new classes). Something that intrigued me was the WebPart classes they introduced.

    Living in the SharePoint space, web parts are the staple at to how to get information out to the presentation layer. In SharePoint they're a little ugly to write, but none the less are effective because the end consumer of the web part can choose how to display it (based on preferences through SharePoint for that particular instance of the web part). This includes appearance, what options they want to display, where they want it on the web page, etc. All of this fits into a nice framework and even allows you to have multiple copies of the web part with them pointing at different views or data sources. One persons way of using a web part may be different then someone else, either by design or organization. For SharePoint, this was the innovation that allows us to build applications on that platform with little effort and target content to specific audiences.

    When I saw the WebPart classes introduced in the 2.0 framework I started salivating. Bringing the capabilities of web parts to regular ASP.NET apps meant that I could introduce things like personalization and customization to apps without having to have to do a lot of work. Web Parts are similar to web user controls but provide the functionality to allow users to customize the website by adding, deleting, and moving controls around the page based on WebPartZones. Any ASP.NET server control can act as a Web Part but by creating a custom control derived from the WebPart class you gain access to advanced features.

    You can check out the new MSDN paper on Web Parts here. Something to look forward to with your apps and something to keep in mind on how to design your apps today as these new capabilties roll into the framework and enable you to start leveraging more features with less code.

  • Virtual Web Part Development with SharePoint

    With all this talk about Virtual User Groups, I somehow got down this path and wanted to say that there is one and only one (IMHO) way to develop web parts for SharePoint (at least that's the conclusion I've come to). Virtual PC 2004 kicks for this. I was able to take the time to get a new Virtual image setup and decided to get a new SharePoint environment setup in it. With the recent update to Virtual PC, Microsoft has made it a little better (and faster) for this.

    The install of Windows 2003 Server was smooth and getting Windows SharePoint Services running was a breeze. Basically:

    • Create a new Virtual PC image through the wizard
    • Pop in a Windows 2003 Server CD (I'm using Enterprise edition but whatever works for you)
    • Run the install (takes about an hour on a 2Ghz machine with 2GB of memory). You don't need a domain so just create a workgroup for it.
    • Once the install is done, make it a web server through the Manage Your Server setup screen
    • Download Windows SharePoint Services from here and run the setup (10 minutes)
    • Set your IIS to allow anonymous on the Default Web Site and set SharePoint to allow anonymous users by default as Readers
    • Install Visual Studio .NET and optionally MSDN (another hour)

    That's about it and Bob's your uncle. I only had to give it 400MB of memory in the settings and it runs well for running, administration, and debugging. The nice thing is that my local machine sees it (even though it's on a different workgroup than my box) and I can ping it and surf to it by name. Makes for great testing and developing because I can come in as a regular user and since it's running in Workgroup mode there's a Sign In button so I can become whoever I want for testing (Contributor, Admin or a user in a custom group). Much easier than when you're running on a domain with integrated authentication and you pretty much have God access to everything. I also don't have to worry about domains and that whole mess. Note that this setup is for WSS, SPS does require a domain to operate on but you can develop web parts on this environment and use them on SharePoint, you just can't use the SharePoint features like search, etc.

    Try it out if you've got the resources as it makes for a nice easy development setup. Debugging web parts has to be done on the server but that's what the install of Visual Studio is for and the speed is quite acceptable. Also there's a good site here on what OSes work (and what don't) under Virtual PC if you're looking on setting up different configurations (I have a Debian setup as well for some Linux development, nothing like a disposable machine!)

  • I love the UI, I love the UI, I love...

    Well, no. It's all great that you have a nice Domain Object. Grant you, it's now populated with an ugly Id attribute which it slugs around because someone, somewhere decided that it was important enough to save the information into a database and databases need a primary key to find stuff. The problem is when I have to show a list to pick from, one of which is what the user selected previously. My Domain Object has this attribute:

    Name: Author; Value: 21

    And there's a collection of Roles to pick from:

    Name: Reader; Id: 10
    Name: Author; Id: 21
    Name: Administrator; Id: 321

    So I have a simple LookupDTO I use in my UI and Service Layer that looks like this:

    class LookupDTO
    {
      string Name;
      int Id;
    }

    It's generic (all lookups follow the same pattern). Problem is that if you have a collection of Roles you can't just bind it to a DropDownList like this:

    // this returns an array of LookupDTO objects from the service layer
    uiName.DataSource = RoleService.FindListForProject(projectId);
    uiName.DataTextField = "Name";
    uiName.DataValueField = "Id";
    uiName.DataBind();

    Because the values are 10, 21, and 321 and you can't set uiName.SelectedIndex = 21 or else ASP.NET blows it's head up with a boundary problem (it's 0-based). Ugly. I hate the fact that my Domain Object says that it's Id is 21 (because that's the database id that was created when it got saved) but ASP.NET needs a 0 or 1 to let a user pick from. So do I need a mapper for my mapper? And then there's going back that you have to do another mapping. So maybe there's a UI component that has both the "real" value and the UI value? I don't know.

    I'm almost thinking that I should use a Guid in the database, but autoincrement is so nice and easy. A Guid would have it's advantage (other than driving my dba nuts) because I can pregenerate it in my Domain when a real object is created so I don't have to do fancy stuff in my SQL to get the ID that was just created. A common problem with using autoincrement in SQL is that you don't get it before the INSERT call. It's unique. I still think I'll have a problem in my UI layer because setting the HTML for a selected item in a dropdown list doesn't like "A04759E3-509C-42c6-BE27-20562B2BA6CA" as a selected value.

    I know there's a better solution out there to map "real" values to ASP.NET UI controls like dropdown lists that don't like indices that don't match the 0 based counting that HTML creates. There's a good blog by Steve Eichert here on Hooking your Domain Model to the UI. I think we need a good UI Mapper tool/pattern/something to make this a no-brainer.

    There's also a very nice add-in from Manuel Abadia over at CodeProject. It provides two way data binding in ASP.NET and looks pretty simple. You just hook up your collection to the fields on your webpage (through a designer) to set the databindings to your DTOs and call BindToWebForm (or BindFromWebForm). It turns this:

    // populate the webform with the customer data
    lName.Text = cus.Name;
    lSurname.Text = cus.Surname;
    lEmail.Text = cus.Email;
    lAddress.Text = cus.Address;
    lAge.Text = cus.Age.ToString();

    // get the customer data from the webform
    cus.Name = lName.Text;
    cus.Surname = lSurname.Text;
    cus.Email = lEmail.Text;
    cus.Address = lAddress.Text;
    cus.Age = Int32.Parse(lAge.Text);

    Into this:

    // populate the webform with the customer data
    bindingManager1.BindToWebForm(this);

    // get the customer data from the webform
    bindingManager1.BindFromWebForm(this);

    You can check out here. I need to find some time to look at it because this is nuts (or else I'm so out of it I'm missing the obvious). Maybe I haven't had enough coffee to think correctly. Friends don't let friends blog drunk (or semi-awake) might be a more appropriate title for this entry.

  • SharePoint beyond the Intranet

    Okay, let's face it. SharePoint (when appropriately used) kicks as a collaboration tool. I don't know how many times I've been asked about sharing knowledge only to say "well SharePoint can do this". I don't know how many times I've seen teams wanting to cobble together a website with FrontPage or throw up a forum tool or something when "SharePoint can do it" (the struggle with the evil IT empire [our strategy and architecture guys] and how we can't just do what's right vs. correct is a whole 'nuther conversation). Grant you, SharePoint isn't all things to all people, but from a collaboration viewpoint it's pretty nifty.

    My fellow SharePoint lover (hmm, that didn't come out quite right) Amanda Murphy (and a Canadian to boot), posed the question of Virtual SharePoint User Groups. While we're all squibbing away building our intranet solutions, it seems that we might be missing the one thing that SharePoint is great for and the one thing that might bring some order to this chaos. The internet is a big ugly place (as I put on all my blueprints, a nasty stormcloud with the words "big bad interweb") and trying to filter information out at the same time balancing what's worthy is just as ugly. I've got I don't know how many bookmarks that I use to hunt down things, a few dozen RSS feeds, countless forum userids and passwords, yet still information fall through the cracks and I'll stumble across a "wow, I didn't know that" each day.

    Microsoft is making some headway in building Technical Community Sites where like people with like thoughts can meet and swap good stuff. We all know User Groups are a great thing (the .NET one here in Cowtown has some great events and is very value-added IMHO). So Amanda puts in my head the notion of a more global User Group. Still a special interest group around that thing we call SharePoint (or SPS, WSS, or whatever acronym you want to throw out there) but why not extend the very tool itself we use each day to accomodate this? Exactly how to get things going, I'm not sure. I do have a passion for this though and would like to see where it goes.

    Anyways, some food for thought and perhaps an evolution towards a more unified collaboration across virtual boundaries that might make life a little bit easier one day for some of us.

  • Hodgepodge of some (hopefully) useful .NET links and sites

    Was doing some research over the weekend and gathed together some links on patterns and practices and other stuff. Hope you guys find these useful.
     
    Good site with all kinds of patterns around user interface (both web and other). Lots of good ideas here.
     
    I was going through some options of providing online help in web apps and came across this. It's a study done on different techniques applied to providing online help for web application users. Some good ideas and information here on what worked and what didn't.
     
    This may seem silly but tables have TH tags for a reason and web readers (the type blind folks use to read webpages for them) rely on it. One of my biggest beef is the fact that the ASP.NET DataGrid doesn't spit out HTML code that's compliant with these readers. This KB article talks about resolving the problem via a hotfix that went out sometime ago. Just information to watch out for and contains a good link to Watchfire, a website that can check your page for accessibility compliance.
     
    Sample Applications
    Microsoft (and others) have gone to some extents to put together sample applications, reference architecture apps, and other resources to learn from. Some good (some not so good) stuff here if you haven't already seen any of these. That make for great reference when you're looking at how to implement some ideas.
     
    ASP.NET 1.0/1.1 Starter Kits
    Home
     
    ASP.NET 2.0 Starter Kits
    Home
     
    Peer to Peer - .NET Framework 1.0/1.1
    Terrarium
     
     
    Service Orientation Architecture
    Generico
     
    Smart Client - .NET Framework 1.0/1.1
    IssueVision
    FotoVision
    TaskVision
  • The dumbness of a Domain Object

    I've been mulling over some ideas for the past couple of days as I work on a project and came to a bit of a head with regards to the dumbness of a Domain Object. There are some base principles that I try to follow with application architecture:

    • The data access layer only creates or accepts domain objects
    • The service layer is responsible for creating or converting data transfer objects to real domain objects
    • Only data transfer objects are sent between the service layer and user interface

    So first off, maybe some of these principles are not correct. Hey, principles can always be changed (as long as you reapply them everywhere if they do change and adjust accordingly). I'll leave that to the reader to discuss.

    Given these norms, there's a problem (or maybe a question). If the DAL only creates Domain Objects, then it needs to know how to assemble them. After all, it's retrieving data from a source and populating *something*. You could hide the creation in an Assembler or maybe a Factory but still, at some point some data needs to be set as an attribute in a Domain Object meaning that the DAL knows something about the contruction of a Domain Object. The other option is that everything gets assembled in the service layer. If this is the case then why do we even need collections in a Domain Object? They can be dumb and just hold properties that relate to themselves and not worry about things like collections of children.

    So here's an example to try to make sense of what I'm talking about. Imagine you have a Media Center tool where users can view album information, list tracks on an album and update the track information. This gives us some simple objects like so (C# pseudo-code):

    class Album
    {
      int AlbumId;
      string Title;
      string Artist;   
    }

    class Track
    {
      int TrackId;
      string Title;
      int Length;
    }

    In order to know what Track belongs to what Album, I could have Domain Objects that look like this:

    class Album
    {
      int AlbumId;
      string Title;
      string Artist;   
      ArrayList Tracks;
    }

    class Track
    {
      int TrackId;
      string Title;
      int Length;
    }

    Or maybe this:

    class Album
    {
      int AlbumId;
      string Title;
      string Artist;   
    }

    class Track
    {
      int TrackId;
      int AlbumId;
      string Title;
      int Length;
    }

    In the case where I have an ArrayList of Tracks in my Album, I don't need the AlbumId to know which Track belongs where. However, if I have to create an Album object out of my DAL, I now know that I have to create Tracks as well. Am I not putting logic of structure of the application in my data layer now? In the last example, I can have some Assembler make calls to the data layer (1 for the album and 1 for the tracks) and put together an object myself. And if the only reason I'm doing this is so that I can show the user at the UI layer an album and it's related tracks, why does my Album Domain Object even need to know about Tracks?

    This also brings up the question around using IDs everywhere. Remember we have a principle (right or wrong) that the UI only deals with DTOs and knows nothing about the domain or (gasp) the data access layer. End users don't need to know that "Like a Virgin" has an ID of 4532 in the database. However, if they update the title to a track on the album and want the tool to save that information, it means the UI needs to keep track of all this junk in order to send it back to the system for updating (there's no guarantee that two tracks won't have the same name, even on the same album). So going back to our example where I only want to update one single Track.Title property with a new name the user typed in, do I send back an entire AlbumDTO (with an Array of TrackDTOs). Probably not. I only want to update one track so I only send back one TrackDTO which leads me to the idea that:

    • A TrackDTO must be able to exist on its own (for updating the backend from the UI)
    • It needs to keep track of the Album it belongs to (otherwise how do we know what Album it's for when we update it)

    Given this, why should a Domain Object (Album in this case) even bother to have a collection of children (Tracks). So all assembling should be done somewhere other than in the domain objects or data access layer? While this might not be the rule for all Domain Objects, I thought it was something that didn't seem to have a very clear answer (or maybe there is but I'm just missing it).

  • Happy Thanksgiving Canada!

    "As God is my witness, I thought Turkeys could fly!"

    - Arthur Carlson, (WKRP Station Manager) 1978 - after a Thanksgiving promotional stunt went horribly wrong

  • InstallShield AutoUpdate

    I'm not one to usually go non-techie and go down the dark sales path, but I saw something I wanted to mention.

    I picked up a copy of Jasc's Paint Shop Pro Studio. It's basically an uber-version of their Paint Shop Pro product. Anyways, after the install, I ran it for the first time and up came what looked like the Windows Installer Update site. I was a little thrown for a sec because I wasn't sure what was going on? Was I missing a critical update? If so, why was Jasc telling me this? Then I realized that it wasn't Studio but an Install Shield feature. Install Shield Corp has a nice Update Service. It basically gives you a nice web-based interface (like WUS) to check for components of your application and an integration piece to install them. They offer both an Install Shield-Hosted service or you can host it on your own infrastructure. Pretty nifty (although when they don't talk about how much it is online, I'm sure it's a big-ticket item).

    Here's to more installers (especially the free ones like Inno Setup that I highly recommend) to combining these concepts. It would be nice if products built in more updaters themselves like Visual Studio (there is a "Check for Service Updates" but I've never got it to work and you have to go through the Add/Remove Programs to access it). Of course here's an opportunity to maybe build a component that does this easily for people.

  • SharePoint Service Architecture and site updates

    Found this on TheServerSide.NET and felt it was worthy to post:

    A new paper on MSDN looks at the architecture of SharePoint Services beginning with a high level overview of the web server and drilling down to using managed and unmanaged code. This paper is a “must read” for anybody looking to develop applications built using SharePoint Services.

    There’s quite a bit going on under the covers of SharePoint services. SharePoint Services is implemented primarily through an ISAPI filter installed in IIS which accesses unmanaged DLLs installed on the web server. The ASPX pages that make up a SharePoint site are actually a relatively thin veneer over those same DLLs. All of the data is then stored in an MSDE or SQL Server Database. And this is the high level view!

    To read more about SharePoint Services Architecture look
    here.

    For this site, a few new links in the SharePoint and Scrum sections. The site is filling out nicely since I started it 6 months ago, although I wish I could post everyday as there's a lot of great stuff to share. Please feel free to let me know if I've missed anything important or you have something to share.

    Also I've taken a couple of blogs and turned them into articles so you can find them in the sidebar. These were ones where I got some feedback and people were asking a lot of questions so there was interest to keep it around and to the forefront (migration of sites, branding SPS, etc.) I'll add more as they become a reality.

  • Defeated by CVS, Windows, and IIS

    Okay, I'll admit it. I've come up against a techno-combo that just has drained me (and bugs the crap out of me). I'm throwing in the towel and picking up a new one.

    We setup CVSNT at work for team source control in order to adapt to a more agile development lifecycle (PVCS just doesn't work when everyone is refactoring and checking in all the time). We're still using PVCS for our enteprise SCM and when things are ready, they're labeled at checked into our corporate repository (well, that's the plan anyways). It's a nice setup and works well.

    I've been struggling with getting some kind of web interface for CVS working with IIS. Yes, I'm tied down to IIS as our corporate web servers which is fine. So I went out to hunt down all the tools I could find and make work (the ultimate goal is to turn our Projects Portal running on SharePoint into something like SourceForge where you can access the source code from a project website). Talk about painful.

    CVSWebNT was the first stop. After installing ActivePerl I was okay burning through the setup. However Perl really isn't a friendly thing to debug, especially when it's an out-of-process cgi-bin script. So after many tries at hanging IIS and rebooting the server, I gave up. Next seemed like a nice gem called CVS4IIS. VB, ASP, and COM (blech) but okay let's give it a try. Not bad but didn't seem to work and it can't support multiple repositories. Finally I took at look at ViewCVS for Windows. Well, not really official but Russ is doing a good job of getting things going there. Problem is that now I would have to install Python, and the Python for Windows extensions and whatever else is thrown in there. In a corporate environment when you're somewhat limited to using a core set of technologies (Python is not one of them) it's tricky. Pain and suffering all before my 2nd cup of coffee this morning.

    So why isn't there a nice project out there that does this easily? I mean, CVSNT is great. Works well, actually has an installer, and doesn't seem to fall over when you look at it. I'm throwing in the towel on trying to get these things working in our environment but there might be hope. Now I'm charged with looking at writing what should hopefully be a fairly simple ASP.NET application to do this. I mean, how frickin' hard can it be? (famous last words). Here comes NCVSWeb coming soon to a SourceForge site near you.

    I so wish for a Linux server at work. Just one. Just a little one. A copy of Debian and a call to apt install cvs and I'm done.

  • The Mysteries of SharePoint Search

    There's a myth in town. SharePoint searches documents. While the search feature of the SharePoint products is a key element, it's not entirely true that it actually does any searching. Walk with me on this one.

    SharePoint, like a conductor in an orchestra, really just orchestrates a search request. As a conductor doesn't play an instrument, SharePoint doesn't actually do the mechanics of a search, it just makes the request. It's really all about IFilters and the search capabilities they provide. The SharePoint search pages, object model and web services are just facades to access the real workers.

    This conversation came up because, out of the box, SharePoint only searches the following content types: .txt, .htm, .doc, .xls, and .ppt. And this search is not SharePoint but rather SQL Servers full-text search engine. After all, a binary file type (like PDF) can't really be searched unless the searcher knows how to read the format. SQL Server knows how to read the base types and with the addition of new iFilters, you can extend that. You can get additional IFilters for PDF, RTF, MSG, ZIP and other formats from various sources (Microsoft has a few free ones like for RTF). A good source of commercial IFilters is the IFilterShop.

    So next time you try searching for content check to make sure your SQL Server (all content for SharePoint is stored in SQL) has an IFilter that recognizes the format you're looking for. Also a catch is when you do need to add a new search type, make sure you install the IFilter on the SQL Server and not the SharePoint one as it's the mechanic that's actually performing the search and just providing results to SharePoint to present to the user.

  • SPS Customization

    I see (and get) a lot of questions about customizing the look and feel of SharePoint Portal Server. More often than not, this leads to an answer of directly modifying the SPS.CSS files on the server. This always leads to the caveat that this file may be updated with a service pack install or software upgrade. There is a much easier and safer way to do this which will never break.

    In your SharePoint setup, Microsoft has provided a way to specify your own custom style sheet. If you know how style sheets work when a page is rendered, the last style specified (no matter how many style sheet files get loaded) always wins. This is by design but knowing this, and how SharePoint works, is a powerful combo that will let you cleanly mod your portal as much as you want without having to backup/restore files everytime your do an upgrade.

    When SharePoint renders it's portal pages it renders all of it's own internal stylesheets. These are (in order):

    1. ows.ccs
    2. menu.css
    3. sps.css

    Next, it renders any stylesheet you specify in the Site Settings page. Finally it renders the page content. Knowing this means that any style you put into your own stylesheet will override those specified in the Microsoft ones. So now you don't have to go modifying the base files to get the effect you want. Here's a simple example.

    Create a blank stylesheet. Put a single style in it. Let's override .ms-WPTitle which is the style used to render Web Part titles. Your stylesheet should contain this:

    .ms-WPTitle
    {
      background-color: black;
      font-weight: bold;
      font-family: verdana, arial, helvetica, sans-serif;
      color: white;
      padding-left: 6px;
      padding-right: 7px;
      padding-top: 2px;
      padding-bottom: 2px;
      font-size: 8pt;
      text-transform: uppercase;
    }

    This creates a style for the web part titles that displays a white uppercase title against a black background using Verdana as a font. Save this file as "mystyle.css" (or whatever name you want).

    Now you need to tell SharePoint to use this stylesheet.

    1. Select "Site Settings" from your portal
    2. Click on "Change portal site properties and SharePoint site creation settings" from the General Settings section
    3. The last option is for a Custom Cascading Style Sheet. Put in the location of your stylesheet you created above. An additional trick is to use SharePoint to store your own stylesheet so put it in the Document Library of your own portal. That way you don't have to deal with server administrators whenever you want to change your sites look and it gives you a simple document management process to keep tabs on who's working on this file. So our entry would look like this: "/Document%20Library/mystyle.css" (assuming you uploaded it to the site, otherwise use a fully qualilfied UNC to locate the stylesheet, maybe from your corporate web servers)
    4. Click OK to save the changes

    Now refresh the site in your browser. You should see the changes applied to all web parts on your site (Press F5 to refresh or you might have to do a "deep" refresh with Ctrl+F5). Continue to edit this file, making changes with your favorite style sheet editor like TopStyle (or Notepad if you prefer). In no time you'll have a custom stylesheet with the branding you want on your site.

    A variation on creating styles from scratch is to take a copy of SPS.CSS and modify the styles you want by changing your copy of this file. This uses the same technique as above (not modifying the file directly) but gives you a list of all the styles that SharePoint uses rather than building up from scratch. Pick whichever method works for you but the important thing to remember is that you don't have to touch the base SharePoint files.

    Two more quick tips. There's a list of the styles used with a visual reference in the SDK documentation available here. Also in that file is a short piece of Javascript that you can create and put into a content editor webpart to display the styles on the page when you hover your mouse over them. Both are valuable resources to help you when you're customizing your look.

    Here's a full set of MSDN articles published on the subject of customizing SPS:

    Part 1 : Introduction
    Part 2 : Using Templates and Site Definitions
    Part 3: Style Sheet Class Reference Tables

  • Migrating SharePoint Sites

    One thing that comes up quite often is "How do I keep all the work I've done in development and move it to acceptance/production" with SharePoint? Luckily there's a nice command line tool that's bundled with SharePoint to do this.

    SMIGRATE is a tool that can restore sites and move them from SharePoint Team Services (STS) into the new 2003 versions. It can also help you migrate sites from one server to another (or to the same server) in 2003 directly. This blog talks about using it for migration from a development environment to your production one (or test if you prefer).

    SMIGRATE works wonders because a) it migrates all your data, including security and subsites b) you can execute it from any SharePoint server and restore to any server (you have to be SPS/WSS admin on both) c) is simple for moving all your hard work in development into acceptance or production. Using SMIGRATE is pretty straight forward.

    To backup a website:

    1. Enter the following at the command line:
      smigrate -w http://server[/site] -f filename.fwp -u domain\id -pw *
    2. This will prompt you for your NT password. Enter it at the prompt.
    3. Grab a coffee and wait.

    To restore a site:

    1. Create a new site through the portal site creation wizard. Note what the site url is.
    2. When you get to the point of applying a template, stop and close the browser.
    3. Enter the following at the command line from any SharePoint server (where siteurl is the url you used in step #1):
      smigrate -r -w siteurl -f filename.fwp -u domain\id -pw *
    4. Enter your password, grab a coffee, go for lunch or have a siesta.

    There are a couple of gotchas you should be aware of.

    1. When you migrate a site, the new site has to exist. If you've gone through the trouble of creating the site using something like the SPS site creation wizard you'll find you get the site created then try to migrate and it tells you a template has already been applied. The trick is that when you to the screen in SPS where you apply the template to the site, the site is already created. Go ahead and start your migration now and when you're done, the site will be there and ready to use.
    2. Make sure all your dataview web parts and 3rd party components are on the target server. There's nothing like migrating the site then trying to access it, only to find yourself staring at the maintenance page trying to remove invalid web parts. This is especially true of dataview web parts as they are sometimes picky about the pathing to the datasource, especially if you have it pointing at another list on the same site.

    In any case, the tool is a good friend to have so get used to it, try it out and make sure you understand what's going on before you start moving gigabytes of documents and lists onto your production boxes. There's also a good writeup on using the tool here and the online version of the Windows SharePoint Administrators Guide here.

    For those that are afflicticted with GUI-Itis and fear the command line, there's a graphical interface that Renauld Comte created. You can download the file directly from here (note, you still have to run this on your SharePoint server).

  • 6 degrees of Office separation

    As I drift through what seems like an endless rift of links, I stumbled across something fun this morning (okay, I call it fun others would call it a waste of bandwidth)

    This Microsoft Office Quiz is for Windows SharePoint Services, the layer deliverying document libraries and team sites for those that dance the SharePoint dance everyday like I do. I managed to score a perfect 10, but not without struggling over question #5 as I don't use meeting workspaces but it seemed the most logical and you can never go wrong with logic (especially with the Chewbacca Defense). There's a whole schwack of quizzes for all the Office products so if you're feeling particularily geeky and want to impress your friends check out this link.

    Funny how I got there. An email from someone that Kate Gregory referred me to, which prompted me to google Kate to see what she was blogging about, which led me to this post which pointed me to the quiz site. It's like playing the Six Degrees of Separation game but with geeks. Hmmm. I wonder how far away I am to Bill Gates?

  • Document Libraries vs. Area Document Libraries

    Saw something that made my head turn with SharePoint so wanted to throw it out there.

    At the portal level you can create document libraries, lists, etc. in an area. The golden rule has been (and a contention of FAQs all over) is that content in an area uses the permissions set from the area. This is in contrast to a WSS site where the permissions can be applied to each document library differently as WSS sites have no concept of an area.

    However in the creation page for an area there's a new option. You can create a Document Library AND you can create an Area Document Library. I wondered what the difference was. A quick Google-is-your-friend search turned up a message by someone saying that Area Document Libraries use permissions from the area whereas a document library in an area can have it's own permissions set (if you can follow that logic) . This however is not true because a test creating these things in the same area show the option to set permissions still isn't there for either library (at the portal level).

    So the mystery is still unsolved? What's the difference?

  • Testing .NET updates across the enterprise?

    A question today for the bloggers (and readers) out there.

    With a size of the organization I work for (7000+ desktops, 120+ servers) it's hard to do a lot of acceptance testing when something like say a .NET patch/upgrade comes out. With hundreds of web apps out there, there's no telling what will break and what won't and frankly, individual testing on each app is just unobtainable given time and budget constraints the business usually is under.

    So the question is, when something like an update comes out how do you test across the entire enterprise to an acceptable level of comfort? Imagine the scenario if/when the .NET framework is updated from 1.1 to 1.2 (or even the large switch we'll have to make to 2.0). You have hundreds of web apps written in .NET out there. Presentation, business, and data tiers all depending on the framework. It's impossible to run through a manual testing effort on each app. In a perfect world, every app would have a good set of Unit tests which you could run.

    However the testing effort is really around making sure the framework doesn't break something in the environment, but how do you test for something like this? How do you be proactive rather than reactive? How do you mitigate risks with such an update and make the environment management people happy with the change? Thoughts, ideas, comments?

  • Customizing SharePoint Sites and Portals

    Not much of a blog this entry as it's just an aggregation of Microsoft content. I thought however people would be interested in the full set of articles published on the subject of customizing SPS.

    Part 1 : Introduction
    Part 2 : Using Templates and Site Definitions
    Part 3: Style Sheet Class Reference Tables

    PS I haven't got much response from my "What have you done with SPS and get a free gmail account" so I guess that's a bust. I wonder if I had offered up a free copy of Visual Studio.NET Enterprise Architect I would have got a better response?

  • GMail Invitations up for grabs

    Okay. I have 5, count them 5, GMail invitiations available to the first few lucky participants. However, you're going to have to work for your 1 gigabyte of free webmail storage.

    Send me a note on how you used SharePoint in your environment (or for a client). Not just an out-of-the-box install but how you leveraged SharePoint to deliver a business need. The more interesting the better. Screen grabs are great too. Top 5 creative uses of SharePoint get the invites. I'll post the winners on this site in a couple of weeks so submitting your entry means that it may be published.

    Now is that so hard? Okay, so it might blow up in my face and nobody is using SharePoint in a creative way but hey, what the heck. Submit your creative creations (zipped or direct me to a public link) to me via email.

  • Session.SessionId is *not* unique

    A co-worker of mine was trying to detect whether his session expired in an ASP.NET application. Before he discovered Session.IsNewSession, he was using the SessionId variable and comparing it to hidden values and whatnot. He had assumed that when a page was reloaded after the session expired, that a new SessionId would be created. This is not always true.

    There's a countdown timer (by default, 20 minutes) that fires from the first request for a users session. If there is another request efore the timer reaches zero, then it resets the counter and begins again. When it reaches zero, the Session_End event (in global.aspx) is fired, not because of a request but because the timer ran out.

    Session.SessionId might be the same on a postback or page reload. If you're not writing any data to the session, ASP.NET will reuse the Id because from it's perspective it hasn't changed so why create a new one (id, not session)? Session.SessionID is generated in RAM on the server and not a persistent property. It's unique at the time is it created, but not guaranteed to be unique over the course of time. For example, if IIS is restarted it may restart the numbering sequence.

    So use Session.IsNewSession to determine if it's a new session or not. Use Guid.NewGuid() to create something unique (you can store this in a Session variable and check for it later if you want).

    There's a great FAQ on ASP.NET session here in case you're interested.

    Happy coding...

  • Migrating sites from dev -> acceptance -> prod

    One thing that comes up quite often is "How do I keep all the work I've done in development and move it to acceptance/production" with SharePoint? Luckily there's a nice command line tool that's bundled with SharePoint to do this.

    SMIGRATE is a tool that can restore sites and move them from SharePoint Team Services (STS) into the new 2003 versions. It can also help you migrate sites from one server to another (or to the same server) in 2003 directly. This blog talks about using it for migration from a development environment to your production one (or test if you prefer).

    SMIGRATE works wonders because a) it migrates all your data, including security and subsites b) you can execute it from any SharePoint server and restore to any server (you have to be SPS/WSS admin on both) c) is simple for moving all your hard work in development into acceptance or production. Using SMIGRATE is pretty straight forward.

    To backup a website:

    1. Enter the following at the command line:
      smigrate -w http://server[/site] -f filename.fwp -u domain\id -pw *
    2. This will prompt you for your NT password. Enter it at the prompt.
    3. Grab a coffee and wait.

    To restore a site:

    1. Create a new site through the portal site creation wizard. Note what the site url is.
    2. When you get to the point of applying a template, stop and close the browser.
    3. Enter the following at the command line from any SharePoint server (where siteurl is the url you used in step #1):
      smigrate -r -w siteurl -f filename.fwp -u domain\id -pw *
    4. Enter your password, grab a coffee, go for lunch or have a siesta.

    There are a couple of gotchas you should be aware of.

    1. When you migrate a site, the new site has to exist. If you've gone through the trouble of creating the site using something like the SPS site creation wizard you'll find you get the site created then try to migrate and it tells you a template has already been applied. The trick is that when you to the screen in SPS where you apply the template to the site, the site is already created. Go ahead and start your migration now and when you're done, the site will be there and ready to use.
    2. Make sure all your dataview web parts and 3rd party components are on the target server. There's nothing like migrating the site then trying to access it, only to find yourself staring at the maintenance page trying to remove invalid web parts. This is especially true of dataview web parts as they are sometimes picky about the pathing to the datasource, especially if you have it pointing at another list on the same site.

    In any case, the tool is a good friend to have so get used to it, try it out and make sure you understand what's going on before you start moving gigabytes of documents and lists onto your production boxes. There's also a good writeup on using the tool here and the online version of the Windows SharePoint Administrators Guide here.

    For those that are afflicticted with GUI-Itis and fear the command line, there's a graphical interface that Renauld Comte created. You can download the file directly from here (note, you still have to run this on your SharePoint server).

  • A clean way to brand your Portal

    I see (and get) a lot of questions about customizing the look and feel of SharePoint Portal Server. More often than not, this leads to an answer of directly modifying the SPS.CSS files on the server. This always leads to the caveat that this file may be updated with a service pack install or software upgrade. There is a much easier and safer way to do this which will never break.

    In your SharePoint setup, Microsoft has provided a way to specify your own custom style sheet. If you know how style sheets work when a page is rendered, the last style specified (no matter how many style sheet files get loaded) always wins. This is by design but knowing this, and how SharePoint works, is a powerful combo that will let you cleanly mod your portal as much as you want without having to backup/restore files everytime your do an upgrade.

    When SharePoint renders it's portal pages it renders all of it's own internal stylesheets. These are (in order):

    1. ows.ccs
    2. menu.css
    3. sps.css

    Next, it renders any stylesheet you specify in the Site Settings page. Finally it renders the page content. Knowing this means that any style you put into your own stylesheet will override those specified in the Microsoft ones. So now you don't have to go modifying the base files to get the effect you want. Here's a simple example.

    Create a blank stylesheet. Put a single style in it. Let's override .ms-WPTitle which is the style used to render Web Part titles. Your stylesheet should contain this:

    .ms-WPTitle
    {
      background-color: black;
      font-weight: bold;
      font-family: verdana, arial, helvetica, sans-serif;
      color: white;
      padding-left: 6px;
      padding-right: 7px;
      padding-top: 2px;
      padding-bottom: 2px;
      font-size: 8pt;
      text-transform: uppercase;
    }

    This creates a style for the web part titles that displays a white uppercase title against a black background using Verdana as a font. Save this file as "mystyle.css" (or whatever name you want).

    Now you need to tell SharePoint to use this stylesheet.

    1. Select "Site Settings" from your portal
    2. Click on "Change portal site properties and SharePoint site creation settings" from the General Settings section
    3. The last option is for a Custom Cascading Style Sheet. Put in the location of your stylesheet you created above. An additional trick is to use SharePoint to store your own stylesheet so put it in the Document Library of your own portal. That way you don't have to deal with server administrators whenever you want to change your sites look and it gives you a simple document management process to keep tabs on who's working on this file. So our entry would look like this: "/Document%20Library/mystyle.css" (assuming you uploaded it to the site, otherwise use a fully qualilfied UNC to locate the stylesheet, maybe from your corporate web servers)
    4. Click OK to save the changes

    Now refresh the site in your browser. You should see the changes applied to all web parts on your site (Press F5 to refresh or you might have to do a "deep" refresh with Ctrl+F5). Continue to edit this file, making changes with your favorite style sheet editor like TopStyle (or Notepad if you prefer). In no time you'll have a custom stylesheet with the branding you want on your site.

    A variation on creating styles from scratch is to take a copy of SPS.CSS and modify the styles you want by changing your copy of this file. This uses the same technique as above (not modifying the file directly) but gives you a list of all the styles that SharePoint uses rather than building up from scratch. Pick whichever method works for you but the important thing to remember is that you don't have to touch the base SharePoint files.

    Two more quick tips. There's a list of the styles used with a visual reference in the SDK documentation available here. Also in that file is a short piece of Javascript that you can create and put into a content editor webpart to display the styles on the page when you hover your mouse over them. Both are valuable resources to help you when you're customizing your look.

    Note, this is only for SharePoint Portal Server. WSS sites need a custom theme which is a whole 'nuther post and a different technique that I'll walk you through if there's a desire.

  • Stored Procs vs. Dynamic SQL

    Late last year, Rob Howard and Frans Bouma got into a fairly heated debate about this. Frans' position was that stored procs were bad, Rob wanted everyone to use them. This resulted in a fierce blog by Frans, a rebuttal by Rob and hundreds of other bloggers taking either side.

    Anyways, for me, it's back again. I'm rolling together several small applications and have come to a crossroads. Now understanding that I'm a working architect (i.e. a software architect that picks the hammer up once in awhile as opposed to the ones that just draw pretty pictures) so my TSQL is very limited and stored procs, well they're about as alien to me as anything. However the syntax isn't that odd (especially if you're writing simple sprocs) and there are too many advantages to pass it up.

    Now there's always a lot of debate of TSQL vs sprocs and performance. Sure, complicated SQL can be a dog's breakfast when it comes to performance and you can just hand your stored proc over to your DBA and ask him to optimize it (what else is he/she there for anyways?). People will argue that simple statements like a SELECT blah FROM blah WHERE blah = @blah shouldn't be in the database. Why not? And who can tell you that the simple SELECT statement will never change. It only took me a few minutes to grasp the stored proc syntax so it's not all that bad.

    As for things like SQL injection attacks or security, those things are always going to be an issue no matter where your code is. Just write good code and treat the database as a client rather than a consumer. There are some situations (like dynamic tables) where sprocs just fall down but I would take a closer look at your architecture. Do you really need dynamic tables or are you doing it to just cut down work imposed on you?

    So basically, I'm looking to use sprocs even in small projects because:

    • I don't want SQL Code in my application because I don't want an application to have to be recompiled when the database changes
    • The application is there to view or be served up by the data, not the other way around so I don't want the application to have complicated security even in a situation where it's needed. It's much easier to apply role based security to the data than to worry about screens and buttons and domain objects that restrict access.
    • I don't want to send a whack of unencrypted SQL across the network showing off my table names
    • Reusability. Having stored procs available across my enterprise cuts down on the amount of code the developer needs to write.
    • I can put together my sprocs and let my DBAs tune it independently of my application.

    I'm finding a lot of advantages by getting my SQL out of my codebase and I believe the benefits outweigh the long term costs of maintenance. Everyone should come to his or her own conclusions on what is right for them. My preference is to use stored procs for any data manipulation. Even simple SELECT, INSERT, DELETE statements are targets as you never know what optimizations your DBA can make. Your mileage may vary.

  • Some blogging todos...

    There continues to be a lot of (what seems to be) frequently asked questions however either people are not visiting and consuming the great SPS and WSS FAQ sites or something is falling through the cracks. Just a note to let you guys what I'm working on in the SharePoint/.NET space and will be publishing over the next week to help spread the knowledge and hopefully help out some groups:

    • HOWTO on the whole custom filtering thing in SharePoint views. This is a big discussion that gets asked all the time (like how do I filter on something other than [Today]). I'll have a full blog on the various tips and tricks on this.
    • HOWTO customizing email alerts (both in SharePoint Portal Server and Windows SharePoint Services as they're different). Again something that gets asked a lot but isn't crystal clear.
    • CODE my SharePoint wrappers are ready for production and re-use which should help you work with SharePoint through web services. They're pretty robust, support both 2001 (using COM Interop) and 2003 (using Web Services) and can be used in any .NET, COM, Delphi, etc. application. Very cool.

    Also this blog is now aggro'd (my word) on MSDN Canada Blogs now so lots of happy-happy-joy-joy there. More aggregation is better I always say (well, okay I don't ALWAYS say it but... never mind)

  • XP Agile Universe

    Pretty cool stuff happening here in Cowtown. XP Agile Universe is just wrapping up the last day. Last nights festivities were great as Bob Martin gave a wicked (bet you never thought you'd see that word in an Agile blog) Keynote speech, centering around Copernicus and how Johannes Kepler used Unit Tests (and 15th century mathematics) to prove Copernicus' theories of how the Sun was the center of the universe (and how he had to throw out his UML diagrams halfway through because he discovered orbits were eliptical not round). Kepler's laws (orbit of a planet around the sun being an ellipse, orbiting intervals, and squares of the periods of planets) are still in use today and solid. Yes, this all related to Agile in Bob's unique and uplifting way (look for Bob's crumbled up notes on eBay shortly, especially the last one he didn't talk about).

    Eric Evans also gave a great presentation, revolving around his own Domain Driven Design book (which I highly recommend as part of my Programmers Essential Bookshelf). Eric talked about how the domain model is key (and it is) and that your system should be an implementation of that model. Far too often I see teams that tread down the DDD path only to toss away any semblance of a model and go heads-down coding to build a system. At the end of the day, it bears no resemblance to anything originally concieved and is a maintenance nightmare. Again, great words of wisdom from a quiet but smart man.

    Next years conference is to be merged with the Agile Development Converence. The new name is (drumroll please...) Agile United. Now of course our immediate reaction last night was around the Manchester United football club, with a table breaking out into song which I'm sure will carry on the joke for years to come. In any case, it's been a great conference so mark the next one down on your calendar and be sure to attend.

  • Portal Owner QuickStart Guide

    I'm currently setting up a common component repository using SharePoint and was looking at a few ideas for it. One thing that I've always found rather interesting was the Portal Owner QuickStart Guide that gets installed by default when you setup a new portal. This rather lonely web part goes practically unnoticed because it is there as a guide when you setup a portal and, once used, is usually deleted. However it's a powerful user experience tool that you may want to take a second look at.

    When I said it was a web part, it is. It's a very specific web part buried deep inside of the Microsoft.SharePoint.WebControls namespace in the SharePoint assembly. It's not just a simple content web part or a data view. It's a full blown web part that can be customized for your use. The problem is that it's undocumented, not very user friendly to configure and even harder to customize.

    Basically the web part has a custom property called "LinkHtml" that contains pseudo-HTML that will do three things:

    1. Render the text for your link
    2. Send the user to the link when they click on it
    3. Popup an additional link that you can use for help or information

    Here's how you customize the content of your web part:

    1. With the web part on your page click on "Edit Page" from the navigation menu
    2. Select the QuickStart web part and choose "Modify Shared Web Part"
    3. On the tool pane you can specify all the typical web part properties like title, size, etc.
    4. Down at the bottom of the tool pane, expand out the Miscellaneous section
    5. There you'll find the HTML for links field. This is where the magic happens.

    The HTML for links field contains pseudo-HTML that is processed by the web part. Here's a sample that produces one link in a group:

    <TABLE class="ms-ls">
    <TR>
    <TD colspan=2 style="padding-top: 6px;" class="ms-smallheader">
    <SPAN class="ms-announcementtitle">Sample Group</SPAN>
    </TD>
    </TR>
    <TR>
    <TD valign=top><IMG SRC="%LSTBULETGIF%" alt=""></TD>
    <TD width="100%" valign=top class="ms-lsmin ms-vb">
    BEGINPOPUP /SamplePopup.htm ENDPOPUP
    BEGINNAVIGATE /SamplePortalPage.aspx ENDNAVIGATE
    BEGINTEXT Sample Text ENDTEXT
    </TD>
    </TR>
    </TABLE>

    The magic that happens are the following keywords:

    • BEGINPOPUP [insert link to your popup content here] ENDPOPUP
    • BEGINNAVIGATE [insert link to where you want the user to go here] ENDNAVIGATE
    • BEGINTEXT [insert text to show the user here] ENDTEXT

    Note: All three must be present in the HTML for links for the web part to work. Specifying a blank value will render the text incorrectly.

    Another thing the web part does is inject the following javascript onto the page when the portal renders it. This provides the popup window that you specify in each BEGINPOPUP/ENDPOPUP pair (don't worry, you don't have to write this it's included when the web part is added to your page but here for reference):

    function PQSDI(helpUrl)
    {
      window.open(helpUrl,
       
    '_blank',
        '
    scrollbars=yes,
        resizable=yes,
        fullscreen=no,
        channelmode=no,
        status=no,
        toolbar=no,
        menubar=no,
        location=no,
        directories=no,
        width=200,
        height=571'
    );
      return false;

    </Script>

    Once you setup the HTML for links content, the web part will parse it and render out the right HTML to the end user (creating an ONCLICK event to call the PQSDI function when the link is selected).

    Yes, it's ugly to edit and no you cannot change the size/position of the popup window but this does provides a nice alternate facility to present information to the user. Also be careful when editing the content. It's very picky about the formatting and sometimes you'll get it, other times it displays nothing or not quite what you want (I haven't had it invalidate my page or anything). Caveat emptor.

    So you may want to export this thing to a DWP file and save it for later use if you have something new to introduce to your users and want a way to provide a sort of self-training guide. Hope this helps!

  • Comment Policy

    This is my comment policy for this site. It was inspired (and plagiarized for the most part) from KC Lemson's Comment Policy on her blog (she's an uber-cool release manager for Microsoft Exchange Server, check out her blog if that's your thing).

    • I reserve the right to edit, delete, or ignore any comment. I don't delete comments disagreeing with me, but I do delete comments that show offensive or abusive language or behavior, or comments that seem to be from someone misrepresenting him/herself.
    • I reserve the right to turn off support for comments at any time. I generally do this after getting an obvious comment spam, and turn it back on a while later.
    • I reserve the right to ignore any comments
    • I reserve the right to ignore email or phone calls I get via this blog [1]
    • I reserve the right to ignore everything (that pretty much covers it)

    Guidelines/expectations:

    • If you want to ask me a specific question, email me but understand my time is limited so I may not get back to you. I generally don't track all of the comments here.
    • If I know the answer to a question off the top of my head, I will generally answer it within a day or so.
    • If I don't know the answer to a question, I probably won't research it, and I also won't follow up to say that I don't know the answer (it's just too much work for the amount of questions I get, and I see no need to repeatedly go around saying that I don't know anything :-).
    • My deep expertise is in SharePoint, .NET Architecture, Agile Practices, and Software Development and Design. That doesn't mean I know everything about those areas, just that I am much more likely to know the answer or be able to suggest additional areas of investigation for technical problems in those areas.

    [1] Unfortunately, just not publishing this information isn't enough to stop some people from contacting me via those methods. Here's a hint: If I don't make it easy to contact me via phone, it's because I don't want to be contacted by phone. I don't even like it when my coworkers call me, let alone people I don't know, asking me for help with a problem to which I don't know the answer.

    Bottom line... stop spamming me you screwheads!

    Comment Policy inspired by KC's
  • Areas vs. Sites

    This is like the SharePoint version of Freddy vs. Jason (or Aliens vs. Predator if that's your sort of thing). It's a debate that, IMHO, has been asked and answered a thousand times over in the newsgroups and emails but people still are confused. Bill English said it best to me once (and continues with this position which I completely share).

    • SharePoint Areas are for aggregation.
    • SharePoint Sites are for collaboration.

    Read this. Learn this. Live this.

    True, you can use the portal to create document libraries, check-in/out and all that good stuff but it becomes a bit of a nightmare in organization from what I've found. Moving it down to a WSS site and letting the user manage access and all that works much better. Also you can create public areas for the information and let users “publish“ information up to the portal into that area which lets them decide what they want to show. They'll go on in their WSS site adding documents and only pushing up to the portal what others need to see.

     

  • SharePoint Wrapper Assembly and Migration Tool

    I've completed a tool to migrate our documents with version histories from 2001 to 2003. I know SPIN/SPOUT do this en-masse but for our needs, there wasn't a 1:1 mapping with old portal directory structure and new portal. There were some other tools in this space, but I had some fun writing an assembly that bridges between the two. Also the new assembly comes in handy when I want to access SharePoint 2003 and do things without having to deploy web parts or executables on the server (everything is done through SharePoint web services).

    The tool has gone off to QA for our own migration so I'll put together a small spike project with examples on how to use it. I'll include some samples on using the SharePoint wrapper assembly as it's handy to be able to bring up a treeview of all of your sites. I used it for another tool we created for deploying web parts to all sites or deleting lists. It can easily be extended to perform more functions but this was all we needed right now.

    If there's any specific requests for functionality in the assemblies let me know and I'll include them before a release later this week. Just have to package up the code and put together some examples then release everything in a day or so.

  • Do we really need version history of documents?

    This is something that's been bugging me for awhile so I thought I would throw it out there. "Is it really worth keeping version history of documents?". Other than legal reasons, I can't see why any would need version history of a document. Source code. Sure. Absolutely. A document? I'm beginning to think that there's no real reason why history is that important.

    Look at a document. Okay, so you'll be able to go back in time and see that Joe added a paragraph or something. If you use Office, this feature is already built into the product. If it's a binary file of some kind (like a PDF) you really can't compare or track revisioning in the document (yes, Adobe had this feature but you need special tools to use it). The only case I can see is a text file where you can do diffs of the versions, but then why would I really care?

    Retaining history seems to be so important to some, but I wonder if that's really the case? Maybe take a look at your documents and try to justify why you think you need a complete version history. Is it really worth keeping in the long run?

  • The Programmers Essential Bookshelf

    Things have changed since I started programming back in the 80s. However there are a few truths that are universal. Here's my list of the essential books all programmers, designers, coders, architects, etc. should have in their repository. Also if you're hiring new people out of University or something, giving them this stack would be a good way to introduce them into the world.

    Code Complete (2nd Edition!)
    Eric Evan's Domain Driven Design
    Design Patterns
    Kent Beck's Test Driven Development: By Example
    Martin Fowler's Refactoring: Improving the Design of Code
    UML Distilled

    There are a couple of others that are great too (there are more):

    Rapid Development
    The Pragmatic Programmer

     

  • SharePoint Wrappers

    As part of my migration tool that I broke down and wrote, I've created a .NET assembly for accessing both SharePoint 2001 and 2003 systems. It uses PKMCDO internally to talk to the Web Storage System and get information about folder and documents and .NET web services to talk to 2003 servers and sites to perform basic stuff like adding web parts, deleting lists, etc. All you need to do is point it at your SharePoint server so you can build desktop apps or non-SharePoint web apps to do SharePoint functionality. I'll clean up the assembly and make it available this weekend for anyone interested. It's not the perfect solution (using web services it's somewhat limited) but at least you can deal with a SharePoint site as a real object.

  • User Control Container Web Part

    I found a great tip and component that strangely enough has been around for a couple of months. Fons Sonnemans over at Reflection IT created a nice simple SharePoint Web Part that acts like a container for normal ASP.NET User Controls (.ascx files). This makes it dead simple to customize a portal page by adding normal ASP.NET controls to it.

    You simply deploy the web part into your SharePoint environment and then create a custom control (his example uses a simple calculator). Deploy the user control to your web server (not sure if it has to be the SharePoint server) and then specify it in the wrapper web part. Presto. Instant Web Part without having to do all that funky Render code. Very nice.

    There's an updated version of the component here. You can find the original information and v1.0 of the web part here.

  • Got ideas?

    I have some spare cycles coming up and would like to offer my services for anyone looking for "small" web parts or .NET apps that interact and perform
    some function directly with SharePoint Portal Server or the WSS. These are things I want to add to the community so who better to provide ideas than well, the community. A couple of caveats to this:

    1. These are small spike projects not giant enterprise solutions so don't ask the world of me (i.e. I'm not going to build a business automation process engine for you).
    2. I cannot make SPS/WSS do things it's not designed for (like providing a web part that grants folder level security) so don't ask.
    3. There are no guarantees on the work done here and any creations are released to the community with source code for anyone to use. You're just there to get something directly and spark the ideas.
    4. This is not contract work so nothing in return is expected.
    5. Please send me your ideas, wants, desires to bsimser@shaw.ca only please.

    Bring it.

  • Wrapping PKMCDO and Adding documents via HTTP PUT

    So I spent the better part of yesterday struggling with my problem. Uploading documents to a folder is great but don't use Copy/Paste to move them anywhere (unless you enjoy losing all your version information). On Monday I'm going to check out a couple of other migration tools, but one of the things with SPIN (besides the fact it has to run on the server) is that it creates its own document library and sets up it's own META data. For us, this just isn't working so we need to look elsewhere for an option.

    I put together a simple document migration tool. I was tired of migration tools that brought over all the wonderful properties, security settings, etc. and all had to run on the server. What the hell is that all about? WSS is about the web. Anyways, there were two problems I had to solve. “How do I get all the versions out of the old Document folders?” and “How do I get all the documents into their new homes?”. Plain and simple. Just copy all versions from 2001 to a target location on 2003.

    For this I did two things. First I wrapped up PKMCDO (the COM interface to SharePoint 2001) into a couple of C# classes. This lets me access everything in a nice way and doesn't expose me to KnowledgeFolders, Recordsets and all that ugliness. I created a SharePointServer class that I can connect to and get the workspaces. This hides a COM interop class to the KnowledgeServer interface:

    /// <summary>

    /// This class wraps up the entire 2001 server for the

    /// purpose of accessing workspaces, folders and documents

    /// within.

    /// </summary>

    public class SharePointServer

    {

          private string serverName;

          private ArrayList workspaces;

          private SharePointFolder documentRoot;

          private KnowledgeServer server;

     

          public SharePointServer(string name)

          {

                documentRoot = null;

                server = new KnowledgeServer();

                serverName = name;

          }

     

          #region Accessors

          public string ServerName

          {

                set { serverName = value; }

          }

     

          /// <summary>

          /// Returns the workspace list for a server.

          /// Will load it on demand if it hasn't been

          /// done yet.

          /// </summary>

          /// <returns></returns>

          public ArrayList Workspaces

          {

                get

                {

                      if(workspaces == null)

                      {

                            workspaces = new ArrayList();

                            ADODB.Recordset rs = (ADODB.Recordset)server.Workspaces;

                            while(!rs.EOF)

                            {

                                  string url = rs.Fields["DAV:href"].Value.ToString();

                                  workspaces.Add(new SharePointWorkspace(url));

                                  rs.MoveNext();

                            }

                      }

                      return workspaces;

                }                

          }

          #endregion

     

          /// <summary>

          /// Gets the document root for a given workspace on the server.

          /// Will load it on demand if it hasn't been created yet.

          /// </summary>

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

          /// <returns></returns>

          public SharePointFolder GetDocumentRoot(string workspaceName)

          {

                if(documentRoot == null)

                {

                      StringBuilder folderUrl = new StringBuilder();

                      folderUrl.Append("http://");

                      folderUrl.Append(serverName);

                      folderUrl.Append("/");

                      folderUrl.Append(workspaceName);

                      folderUrl.Append("/Documents");

                      documentRoot = new SharePointFolder(folderUrl.ToString());

                }

                return documentRoot;

          }

     

          /// <summary>

          /// Connects to a SharePoint server for accessing

          /// workspaces, folders, and items.

          /// </summary>

          /// <returns></returns>

          public bool Connect()

          {

                bool rc = true;

                     

                // Build the string for the server and connect

                StringBuilder serverUrl = new StringBuilder();

                serverUrl.Append("http://");

                serverUrl.Append(serverName);

                serverUrl.Append("/SharePoint Portal Server/workspaces/");

     

                server.DataSource.Open(

                      serverUrl.ToString(),

                      null,

                      PKMCDO.ConnectModeEnum.adModeRead,

                      PKMCDO.RecordCreateOptionsEnum.adFailIfNotExists,

                      PKMCDO.RecordOpenOptionsEnum.adOpenSource,

                      null,

                      null);

     

                return rc;

          }

    }

     

    It's still slow (COM interop always is) but it works and now I can do nice things like a foreach statement iterating through folders. I also created a SharePointFolder class which wraps up the functions for a PKMCDO KnowledgeFolder (like getting the subfolders). Here's part of that class:

     

    /// <summary>

    /// This represents a wrapper class to more easily

    /// use the PKMCDO KnowledgeFolders object for accessing

    /// Sharepoint 2001 items. It uses COM interop so it's

    /// slooow but it works and at least you can use C# iterators.

    /// </summary>

    public class SharePointFolder

    {

          private string folderUrl;

          private KnowledgeFolder folder = new KnowledgeFolder();

          private ArrayList subFolders = new ArrayList();

     

          /// <summary>

          /// Constructs a SharePointFolder object and opens

          /// the datasource (via a url). COM interop so its

          /// ugly and takes a second or so to execute.

          /// </summary>

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

          public SharePointFolder(string url)

          {

                folderUrl = url;

                folder.DataSource.Open(

                      folderUrl,

                      null,

                      PKMCDO.ConnectModeEnum.adModeRead,

                      PKMCDO.RecordCreateOptionsEnum.adFailIfNotExists,

                      PKMCDO.RecordOpenOptionsEnum.adOpenSource,

                      null,

                      null);

          }

     

          /// <summary>

          /// This loads the subfolders for the class

          /// if there are any available.

          /// </summary>

          public void LoadSubFolders()

          {

                if(folder.HasChildren)

                {

                      ADODB.Recordset rs = (ADODB.Recordset)folder.Subfolders;

                      while(!rs.EOF)

                      {

                            SharePointFolder child = new SharePointFolder(rs.Fields["DAV:href"].Value.ToString());

                            subFolders.Add(child);

                            rs.MoveNext();

                      }

                }

          }

     

          #region Accessors

          public ArrayList SubFolders

          {

                get { return subFolders; }

          }

     

          public bool HasSubFolders

          {

                get { return folder.HasChildren; }

          }

     

          public string Name

          {

                get { return folder.DisplayName.ToString(); }

          }

          #endregion

    }

     

    This allowed me to get everything I needed from the old 2001 server (there are other classes for wrapping up the document and versions). The second problem was how to upload these versions to the new 2003 document library. Just upload the document. That's all I wanted to do.

    There seemed to be a lot of argument about using Web Services, lists, and all that just to upload a document. It can't be that hard. After spending a little time on Google (google IS your friend) I found various attempts at uploading documents through regular HTTP PUT commands. Here's the one that finally worked in a simple, single function:

    /// <summary>

    /// This function uploads a local file to a remote SharePoint

    /// document library using regular HTTP responses. Can be

    /// included in a console app, windows app or a web app.

    /// </summary>

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

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

    public void UploadDocument(string localFile, string remoteFile)

    {

          // Read in the local file

          FileStream fstream = new FileStream(localFile, FileMode.Open, FileAccess.Read);

          byte [] buffer = new byte[fstream.Length];

          fstream.Read(buffer, 0, Convert.ToInt32(fstream.Length));

          fstream.Close();

     

          // Create the web request object

          WebRequest request = WebRequest.Create(remoteFile);

          request.Credentials = System.Net.CredentialCache.DefaultCredentials;

          request.Method = "PUT";

          request.ContentLength = buffer.Length;

     

          // Write the local file to the remote system

          BinaryWriter writer = new BinaryWriter(request.GetRequestStream());

          writer.Write(buffer, 0, buffer.Length);

          writer.Close();

     

          // Get a web response back

          HttpWebResponse response = (HttpWebResponse)request.GetResponse();

          response.Close();

    }

    To call it, just pass it the name of a local file and the name of the fully qualified file to be uploaded on the server (document library and filename). You could also modify the code to accept a stream and read the stream in from a web page. Or process an entire directory at once. “Shared%20Documents“ is the name of the Document Library on the site. I'm not sure if you need the %20 or not, and it might be better to use a System.Uri object instead of a string here, but it works.

    string localFile = "c:\\test.doc";

    string remoteFile = http://servername/sites/sitename/Shared%20Documents/test.doc;

    UploadDocument(localFile, remoteFile);

     

    Easy stuff. Let me know if you want the full source to my PKMCDO wrappers and the migration tool. I may end up posting all the code, but I have to finish it and do some unit testing on it.

  • Working on a simple document migration tool

    I'm kinda fed up at the migration tools for SharePoint (and maybe I'm just still steamed at the fiasco I went through yesterday). Using SPIN and SPOUT was to get everything (with history) from 2001 to 2003. My plan was, once migrated into the SharePoint Document Libraries, to just copy these things down to where they belong. Now I'm on the warpath to write a proper migration tool. One step read from 2001 to write into 2003. It's all there via Web Services and the old SharePoint 2001 OM. Why is this so difficult? All the tools that Microsoft gives you are for mass migrations and assume you want to maintain security and copy all the profiles, etc. 2003 is a completely different beast architecturally and makes you think differently about the way your organize your information. Yes, there are some other commerical tools that might do this but again these are just not quite right. And to top it off, nothing ever seems to work from your desktop. You have to be running right on the SharePoint servers directly. This is just not right and I'm out to fix it (somehow). Back later with the results of my madness...

    One other note from yesterdays blog, Addy Santo has posted a commont about an an excellent deployment tool which assists both in migrations and deployments, and can take most of the pain out of the process. There wasn't much to check out but I'm going to investigate this and see if this can assist with what I'm trying to do here.

  • SharePoint 1 - Bil 0

    Okay, I'm a little frustrated tonight and have expereienced, in full featured dyno-rama glory that which I call SharePoint and the beast known as WebDAV (warning this is a little long but does contain important info about a problem with Explorer View and SharePoint). Caveat Emptor: This is the situation for me in my environment (Windows 2003, SharePoint Portal Server/WSS, Windows 2000 Client and Office 2003). Maybe I've just been up too much watching the Calgary Flames but I do think there's a problem here (and hoping my MVP buddies will help confirm/deny my findings).

    Ever since I saw the 2003 version of SharePoint, the WSS and those wonderful features my mouth was watering. What a great improvement over what we currently had. One nice feature was the Explorer View in the document libraries. Now, through the web browser, you could drag and drop files and view your SharePoint site like you do your hard drive. Great stuff.

    Tonight I discovered the pain that is WebDAV, the SPIN and SPOUT tools and how things are not always what they seem.

    We're moving about 5GB of documents (10,000 documents or so) from our old 2001 server to the new 2003 system. Great. Of course we didn't do the in-place upgrade as this was a new system so the quest for tools began. Luckily Microsoft came through with SPIN.EXE and SPOUT.EXE which exported all the version history from 2001 into XML and file formats and SPIN.EXE let you import it into WSS document libraries (or SPS areas if that's your thing). Architecture changes, heirachy changes and things are now organized differently in the new world. While the tools exported fine (although taking 4 hours to run over the network) the problem came when trying to put documents in the right place.

    So there are some bugs with Explorer View, and quite frankly I recommend deleting that view until these things are resolved or someone comes along with a better implementation of it. As I understand it, it works using WebDAV to connect to the Document Library. There are three serious problems with the Explorer View which I'll get into more detail:

    1. WebDAV can only handle a certain path length and bombs on long URLs
    2. The Explorer View in your web browser is cached and never refreshed unless you explicitly do it yourself
    3. Copy and Paste is a nightmare in versioned libraries

    Let's get into more detail about these.

    1. If you've ever gone fishing in your SharePoint sites and then clicked on Explorer View only to be informed that the view requires Internet Explorer 5 or higher then you'll know what I'm talking about. It's an odd message because when I get it, I'm running IE 6. So that's not the problem. I've narrowed it down to the fact that the path gets too long. When you get into specific folders in Document Libraries and specific views, the URL gets pretty long. IE can handle anything but when it switches over to Explorer View it starts talking WebDAV to the back end. That's where the view fails and you end up with a cryptic error message.

    2. Here's a screwy thing that took me a few minutes to figure out. Create a Document Library then go in and add a file. Great. Switch to Explorer View (assuming you don't run into issue #1) and behold your document. Flip back to All Documents view and add a folder. Delete a document. Do whatever you want. Now back to Explorer View in your browser. Hmmm. That's not right. It's the same thing I looked at a few minutes ago (sans the changes you just did). I think the Explorer View is cached and the browser is using that cached version. Hitting F5 doesn't work because that's only going to refresh the web page, not the folder view. You have to right click and select Refresh from the popup menu (yes, a different refresh from the browser one).

    3. Okay, here's the grand daddy of them all (and it gets complicated so walk with me on this). DO NOT USE COPY AND PASTE IN VERSIONED LIBRARIES! Hmm. Got the message? Here's the rundown.

    1. Create two Document Libraries (“doclib1“ and “doclib2“) and set versioning on (can be in the same site, doesn't matter)
    2. Create a text file with Notepad or something (“ver.txt“) with the words “Version 1“ in it
    3. Upload “ver.txt“ to “doclib1“
    4. Check it out via the menu
    5. Edit your “ver.txt“ file on the hard drive and change the text to “Version 2“
    6. Upload “ver.txt“ (modified) to “doclib1“ (overwriting any current copy)
    7. Use the menu and check the file in

    Looking at the version history, you now have two versions. Click on the first one and you'll see the text “Version 1“. Click on the second (and hit F5 in your browser) and you'll see “Version 2“. Also notice that there's a new path created for version 1 of the document (if you hover over the link in the document library).

    Now the fun begins. Switch to the dreaded Explorer View in “doclib1“. Select your “ver.txt“ file and press Ctrl+C (Copy). Now go find “doclib2“ and switch to Explorer View (dual monitors makes this much easier). Press Ctrl+V (Paste). Voila. You now have “ver.txt“ in your new Document Library. Wait a minute. Something isn't quite right. The version comments (if you had any) all say the same thing as the last version. Click on the file to view the Version History. You'll notice the right number of versions (two in this example, but if you had 10 in “doclib1“ you'll have 10 in “doclib2“). However they're ALL THE SAME VERSION! Yup, SharePoint created multiple “versions“ of your document but they're all copies of the latest one.

    There's actually two different behaviours here. Copy/Paste from one Document Library to another in the same site yields this result. However try this by Pasting into a Document Library on another site is a whole nuther matter. Try it and view anything but the latest version. SharePoint lists the versions but they don't exist. In fact, nothing does. It's odd. Clicking on the file produces a web page that goes to HTML Valhalla. There's no 404 error. Right click and View Source and there's a complete absence of anything. No HTML tags. Nothing. Very, very odd.

    Anyways, as I said earlier your mileage may vary but if you can confirm item #3 I suggest you do one of two things. Do not using versioning in your document libraries or delete the Explorer View. Hopefully this will help, now I just have to figure out how to move all my version histories to the right places.

  • Remembering Design Principles

    After taking a look at NDepend and running it on a few projects at work, most of the assemblies seem to either be living in the Zone of Pain or the Zone of Uselessness. While I'm not using NDepend as the silver bullet to tell me who's been naughty or nice, I am wondering how many basic design principles have been forgotten (or some cases never learned in the first place).

    The common ones that I keep going back to (and evangelise to those that care) are:

    There are others, but these are usually the most common and most violated as I keep looking at other peoples code (and my own for that matter).

  • Design Quality Metrics for .NET Applications

    I've been struggling with a concept at work. How to measure the quality of an application? It's typical to ask and there are some basic things you can look at, but for the most part you're doing code reviews or looking through architecture diagrams trying to figure out what someone built and is it good.

    Now along comes NDepend. It analyses .NET assemblies and generates design quality metrics around them. You can measure the quality of a design in terms of extensibility, reusability, and maintainability. Prety nice stuff and of course, open source (yay for OSS!). You can check out the latest version of NDepend here and check out a sample report of NDepend run against NUnit here. Neat stuff.

  • Unit Testing with SharePoint Web Parts

    In my experiences, one of the best things you can do (if you do any XP practice at all) is to write Unit Tests. These are a small, focused set of tests that perform some specific testing of the system. For an overview of Unit Tests check out this link here. In the .NET space, NUnit is my preferred Unit Test framework. Your milage may vary.

    When writing Web Parts for SharePoint, you can apply the same practice to your web part and exercise the Unit Tests using the NUnit GUI (or NUnit command line if you prefer). First download NUnit from here and install it to your development environment and on the SharePoint server.

    How you setup your tests are up to you (and what dependancies your web parts will need) but try to position the Test Fixture up as high as you can on the SharePoint tree, holding whatever information you need. Get a reference to the entire web collection if you want so that way your tests don't have to tax the SharePoint server too much when running. Then just manipulate the collection during your tests. As long as you clean up after yourself (like deleting a site after creating it) everything should be fine.

    Here's a sample test for a custom webpart that creates new sites (using the SPWebCollection class). The Test counts the number of existing sites and stores it and then adds a new site and tests the count (you could also find the test using a query or something but this is a simple example). The test uses data from the web part for input into the site creation process (name, description, etc.):

    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Xml.Serialization;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebPartPages;
    using Microsoft.SharePoint.Utilities;
    using System.Web.UI.HtmlControls;
    using NUnit.Framework;
    using CustomWebPart;

    namespace CustomWebPart.Test
    {

    // This is our custom web part which
    // has some public properties for the new site
    private CustomWebPart webPart;
    private SPWeb webSite;
    private SPWebCollection siteCollection;
    private string currentTemplate;

    [TestFixtureSetUp]
    public void Init()
    {
        webPart = new CustomWebPart();
        webSite = new SPWeb(“http://Server_Name//sites//Site_Name“);
        siteCollection = webSite.Webs;
        currentTemplate = webSite.WebTemplate;
    }

    [Test]
    public void TestAddSite()
    {
        string siteName = webPart.SiteName;
        string siteDescription = webPart.SiteDescription;
        string siteUrl = webPart.SiteUrl;
        int siteCount = siteCollection.Count;
        // Add the new site
        siteCollection.Add(siteUrl, siteName, siteDescription, Convert.ToUInt32(1033), currentTemplate, True, False);
        int newCount = siteCollection.Count;
        Assert.AreEqual(siteCount+1, newCount, “Invalid site count“);
        // delete the site we just created
        siteCollection.Delete(siteName);
    }

    }

    You can reference any part of your Web Part or invoke a method on it to help with your tests as needed. As well, once you create a connection to a SPSiteCollection or SPWebCollection you can iterate through sites or get individual sites and perform any tests on them. Just keep your tests clean and simple and only test what you need to as it relates to your Web Part.

  • Settling in and linking to the world

    Okay, I've got this .Text thing down pat now. I've been blogging for a few years now with the original sin, Blogger (wayback before Google capitalized on it when it was just a spark in Evan's eyes). Now I'm juggling a few blogs on various subjects but I'm happy with where things are.

    I did have to spend a couple of hours tonight (which I'm sure people will consider a waste) copying all my RSS bookmarks into RSS Bandit so now I've got a single source for my geek-news aggregation. I've also added the noteworthy ones to this site in the appropriate categories (mostly SharePoint). Of course this meant I had to go through an exasperating sequence:

    1. Launch the site in my browser
    2. Copy the shortcut to the RSS feed
    3. Create a new feed in RSS Bandit
    4. Create a new link in this site
    5. Paste the RSS link
    6. Copy and paste the web URL
    7. Enter the name of the site
    8. Lather, rinse, repeat

    Whew. Well, now that that's done it's over. Bandit is happily churning away grabbing news and telling me when something I might consider useful in the world changes, which is a much better model than me visiting a few dozen websites looking for something useful (and usually finding dribble). I highly recommend RSS Bandit (or similar news aggregator, but Bandit is Open Source and written in .NET) to get on top of these things.

    I've also added a new link group called Articles. .Text is a great system and lets you post articles rather than blog postings for whatever you see fit. The recommendation is to create a post in your blog about an article with a link to it, but after that blog rolls off your active list how can you access it? So the brain fart came over me to create a link group called Articles and post them there. I've added the first one that I'm pretty proud of which is a Workshop template you can use to ease people into Adopting Agile Practices into the Enterprise. It was assembled from some ideas I've had and tidbits of info I found on the net around the benefits of Agile and XP. I've applied it to a typical waterfall type development group/PM where I work with a lot of success. I'm planning on getting all new .NET development following it in the new year so if you have any suggestions on the content feel free to leave a comment in the article. I'll be updating it as I find tweaks to the Workshop.

    Finally I imported a large MVP list into my MSN so for those of you who are wondering who the heck is this guy it's me. Pay no attention to the man behind the curtain.

  • Hello World

    Well, I made it with few scars and most of my body parts intact.

    This is probably the 4th or 5th blog I've setup on the net but the first that's specific to .NET and various other Microsquishy topics. I set up home here as I'm now officially a Microsoft Most Valuable Professional (MVP), getting my award back in April of this year. Microsoft MVPs are acknowledged by peers and also by Microsoft for their active participation in Microsoft technical communities around the globe. My MVP award came as a result of my participation in the SharePoint community. Over the last couple of years, I've become quite intimate with the Microsoft Portal product introducing it to my organizating (CP Rail) and getting people doing things differently with document management and mentoring people on what a “portal” really is.

    This week I'll be hosting an Ask-The-Experts booth at the TechNet Canada Spring Tour in Calgary on June 3rd. The event will begin with an overview of best practices and strategies for ensuring client and server security. In the afternoon, we'll also review the new features of Microsoft Systems Management Server (SMS) 2003, and show how SMS 2003 integrates with Network and Operating System Technologies such as Active Directory and Windows Management Instrumentation. The event will conclude with a look at the new features in Windows Small Business Server 2003 starting with a fresh out-of-the-box installation. Feel free to approach me and chat with anything and they'll be some goodies you get courtesy of Microsoft. The Calgary event will take place at the regular location, Paramount Chinook down on McLeod Trail. Information and registration can be found here.

    Anyways, so I'm off and running on this blog now. I have to thank Scott Water and .Text for this site and the ease to post my info here. I just have to figure out how to configure this site and add more info. I'll be posting blog snippets of .NET code, SharePoint tips, Agile software development techniques and experiences and whatever else comes along the way.

  • Adopting Agile in the Enteprise - The QuickStart Workshop

    If you're having difficulty adapting agile development at your workplace or just need a helping hand this document might help out. This is an outline that I've prepared at my work to do just that. It outlines a proposal and plan for hosting an Application Development QuickStart Workshop. Feel free to adapt it for your use but it's been generalized enough so that it should fit into any IT departement.

    Introduction

    The QuickStart Workshop is meant to get development teams up and running with new application development quickly and easily and down the path to success. This is accomplished through:

    • Creating an agile development environment for the team
    • Engaging the team in an intense development session
    • Practicing best of breed attributes of Agile Development. This includes eXtreme Programming, Iterative Development, and Test Driven Design
    • Creating a solid application design and reference architecture to start from
    • Producing the first iteration of an application to continue growing it throughout the development lifecycle

    The workshop is customized to fit each project teams needs. By utilizing a series of options, you will leverage each members time for the greatest benefit.

    Why Not?

    The big question is why wouldn’t you adopt this workshop and practice it? The big reason is that the benefits listed below will be immediately recognizable in your project and your team dynamics. In comparison to traditional development you can see the differences below:

    Traditional Development Agile Development
    Long, “big-bang” delivery cycles Short, frequent delivery cycles
    Process-driven Business value-driven
    Comprehensive documentation Working software with minimal documentation
    Contract Collaboration
    Minimize change Embrace change
    Specialization

    Empowered teams

    What does the Workshop provide?

    • An understanding of the agile processes and methodology, emergence, self-organization, and adaptation
    • An understanding of how to manage emerging requirements and unstable technology and still provide guaranteed business value within a fixed cost and time.
    • A preliminary product backlog of project requirements to drive the first several iterations and an understanding of how to manage the product backlog.
    • An understanding of how to plan and initiate iterations from product backlog.
    • An iteration plan for the first iteration.
    • An understanding by the team of how to self-organize and work with emerging requirements, architecture, and design.
    • An optimized work environment and infrastructure for the team.
    • An understanding of the theory, practices, and values that underline agile processes. At the end of the workshop, the team will be well on its way to its first iteration to create an increment of user functionality for the project.

    Practices Experienced During the Workshop

    The Workshop is focused on delivery and collaboration. It helps teams get to know and follow most of the 12 core practices of the eXtreme Programming model (XP). These practices are not necessarily followed to the letter, but the intent is to provide the exposure to them where it makes sense. These are:

    • The Planning Game: Business and development cooperate to produce the maximum business value as rapidly as possible. The planning game happens at various scales, but the basic rules are always the same:
    • Business comes up with a list of desired features for the system. Each feature is written out as a User Story, which gives the feature a name, and describes in broad strokes what is required. User stories are typically written on 4x6 cards.
    • Development estimates how much effort each story will take, and how much effort the team can produce in a given time interval (the iteration).
    • Business then decides which stories to implement in what order, as well as when and how often to produce a production releases of the system.
    • Small Releases: Start with the smallest useful feature set. Release early and often, adding a few features each time.
    • System Metaphor: Each project has an organizing metaphor, which provides an easy to remember naming convention.
    • Simple Design: Always use the simplest possible design that gets the job done. The requirements will change tomorrow, so only do what's needed to meet today's requirements.
    • Continuous Testing: Before programmers add a feature, they write a test for it. When the suite runs, the job is done. Tests in XP come in two basic flavors.
      Unit Tests are automated tests written by the developers to test functionality as they write it. Each unit test typically tests only a single class, or a small cluster of classes. Unit tests are typically written using a unit testing framework, such as NUnit
    • Acceptance Tests (also known as Functional Tests) are specified by the customer to test that the overall system is functioning as specified. Acceptance tests typically test the entire system, or some large chunk of it. When all the acceptance tests pass for a given user story, that story is considered complete. At the very least, an acceptance test could consist of a script of user interface actions and expected results that a human can run. Ideally acceptance tests should be automated, either using the unit testing framework, or a separate acceptance testing framework.
    • Refactoring: Refactor out any duplicate code generated in a coding session. You can do this with confidence that you didn't break anything because you have the tests.
    • Pair Programming: Code is written by two programmers sitting at one machine. Essentially, all code is reviewed as it is written.
      Collective Code Ownership: No single person "owns" a module. A developer is expected to be able to work on any part of the codebase at any time.
      Continuous Integration: All changes are integrated into the codebase at least daily. The tests have to run 100% both before and after integration.
      40-Hour Work Week: Programmers go home on time. In crunch mode, up to one week of overtime is allowed. But multiple consecutive weeks of overtime are treated as a sign that something is very wrong with the process.
    • On-site Customer: Development team has continuous access to a real live customer, that is, someone who will actually be using the system. For commercial software with lots of customers, a customer proxy (usually the product manager) is used instead.
    • Coding Standards: Everyone codes to the same standards. Ideally, you shouldn't be able to tell by looking at it who on the team has touched a specific piece of code.

    Benefits

    The benefits of participating in the workshop come to bear quickly for each team. They are tangible and measurable and include:

    • Understanding the application design and architecture process and how a team fits in
    • Collaborating as a highly effective team working towards a single goal
    • Learning new practices and technologies like .NET, Agile and iterative development, and Test Driven Design
    • Managing change successfully by not fearing to change code in the system or completely throwing away concepts that don’t work
    • A working and fully tested system at all times which delivers and evaluates the business value on an on-going basis
    • Creation of re-usable components and services that other projects, teams, and the enterprise can leverage to reduce future development cycles

    In addition to the benefits above the workshop adheres to the following practices which are tied to direct benefits:

    Development Practice Benefit
    Capturing business requirements in a form that can be estimated and prioritized within the overall product development. Provides the business with control over the cost and scope of the project, while encouraging an iterative release cycle that puts the highest priority features into production first.
    Test-Driven Development describes the practice of writing unit-tests for a product feature before writing the code for the feature itself. The growing suite of unit-tests forms a regression test framework that is run tens if not hundreds of times per developer per day, during the development lifecycle. Unit testing is required for production quality code, hence writing unit tests before writing code ensures that all code is production quality at all times. Regression suite ensures that new features cannot break existing functionality, giving developers the courage and confidence to make major technical or business changes without fear of failure.
    Continuous Integration describes the practice of integrating each developers code changes into the overall project, as soon as their unit tests are passing and their code is complete. Continuous integration involves running the full-suite of unit tests, tens of not hundreds of times a day, alerting the team instantly should a previous piece of working functionality be compromised development lifecycle. By putting integration and testing into the heart of the development process, the financial cost of integrating and testing code at the end of a development cycle is reduced. Furthermore, since this testing cycle typically occurs immediately prior to a fixed milestone such as a product launch, it is often omitted through necessity - by integrating and regression testing continuously, this quality compromise does not occur.
    Refactoring describes the agile practice of changing the design of existing code to a more elegant solution. Rather than invest in a period of "big up-front design", an agile software development only ever implements the functionality that is required by the business, reducing time to market, reducing cost, whilst dramatically reducing the opportunities for software failure. The existence of a comprehensive regressive test framework supports this practice of refactoring.

    The mixing of quality practices and quality methods ensures that the risk, cost and scope of a software project are visible and manageable by the client. In software development, escalating costs, slipping timescales and poor quality are establishing themselves as the norm, rather than the exception.

    Engaging the Workshop

    The Workshop is a part of the application development kick-off and the first thing that happens with the project team. The requirements to engage the workshop are:

    • Use Cases or requirements around the basic goal of the system. These do not need to be completed to perfection but there needs to be some kind of idea in mind of the goal for the project. These can be as simple as the high level Use Cases that come out of the concept phase of a project.
    • A team or core group of developers with an eagerness to deliver
    • 3 to 10 contiguous days of time allocated by the group. No meetings should be booked during this time. The length depends on the size of group and project but will not exceed more than 2 weeks (10 days).
    • If possible a customer/business user or representative who is comfortable with defining requirements for a system

    Workshop Schedule

    The workshop schedule will vary from project to project but basically it kicks off with the following activities:

    1. Project Initiation and Charter
    2. Iteration Planning
    3. Shape Architecture
    4. Monitoring and Reporting
    5. Requirements Gathering
    6. Delivered-feature Contracts
    7. Facilitating Change
    8. Peer-to-peer collaboration: paired programming, test-driven development and design, unit testing, daily Scrum meetings

    How Do I Start?

    The big question would be how do you start this practice, get a workshop going and continue the practice with your team. Here’s a possible suggestion:

    1. Setup a ½ or 1 hour session to determine the size and scale of the workshop. You can orchestrate this yourself or contact a group that might help you facilitate this like a core Development Services team.
    2. Allow for 1-2 weeks lead time to orchestrate the facilities (room bookings, software installations, etc.). Have the team clear their calendar for the duration of the workshop. The workshop may finish early, but be prepared for the entire length of the workshop.
    3. Setup a 1 hour kickoff meeting prior to the first day of the workshop. This will set expectations of the workshop, discuss any questions about how things will progress, and lay the ground rules during the workshop. This ensures everyone is comfortable with the process and knows what success means to them.

    Like any journey, everything begins with a first step. It is not, however, the last step. Each project will engage the workshop differently and as teams become familiar with the practices being engaged here, the duration of future workshops will become shorter. You should provide “booster” workshops as a refresher from time to time. Not only will teams change, but the underlying practices will as do the projects and technologies involved. This will evolve as time goes on and help keep your development teams running smoothly and be effective units of work.