20 November 2008

SharePoint Guidance: Comments

In November, Microsoft released the SharePoint Guidance document under their patterns & practices section. The idea of centralized best practices for SharePoint is a compelling one as the bulk reference for the platform is based in loose information from various blogs and discussion forums.

After reviewing the document, I felt that some comments and questions were necessary.

List Definition Authoring Tools

The SharePoint Solution Generator from Microsoft has been around for a long time, but I frequently use the CodePlex MOSS Feature Generator which contains many additional features. There are a few issues with the application, most noticeably that any custom content types are incorrectly referenced in the content type reference section within the schema.xml file (as of version 0.7). Still, it's a great tool.

Workflow Implementation

See previous comments on workflow templates and debugging and debugging issues.

Unit Testing, Continuous Integration and Test Driven Development

As said already, there is a lot of discussion around mocking. What I feel is missing is a general overview of unit testing as mocking is primarily used for Test Driven Development (TDD).

Many developers come from a background where web parts and SharePoint features are thrown together quickly and without any test plans, UATs, integration testing or regression testing. To go directly to mocking and TDD might be both overkill and too steep a learning curve.

First we need to ensure that our code is written to support TDD and unit testing by making isolated compartments of code that can be tested using some sort of interface and that method arguments are properly validated. This is basic object orientation and code practice, but I frequently see "spaghetti code" used within SharePoint development, such as web user controls exposed publicly within controls.

Personally, I would ideally like to see TDD used for unit tests, ensure adequate code coverage of all unit tests (I use NCover), automated browser tests and unit tests for regression testing (I use the WatIN framework to create automated browser tests) that attempt to complete each step of the UAT tests and manual testing of all UATs and definitions of done/conditions of acceptance.

Apart from that, all tests needs to be continuously reviewed in order to detect new defects and integration issues. The Team Foundation Server integration build, as mentioned under continuous integration in the document, could take care of this, but it would not be enough to build the solution and run the mock tests.

In a current project, I wrote a continuous integration extension for Team Foundation Server and SharePoint that automatically

  • Retracts and deploys the latest build of the feature(s) across a separate test farm
  • Recreates the site collection using the latest site definition
  • Runs all unit tests and regression tests and copies the report to the TFS build drop folder
  • Compiles the SandCastle documentation file for all projects within the solution
  • Puts the solution file (wsp), the setup files and the documentation to a sub folder in the TFS drop folder that can be accessible via secure FTP

This approach gives a more complete test plan than using mocking on its own.

Feedback

Please submit any additional comments and feedback on either the document or my comments below. It is important for the community to respond to this document in order for it to evolve!

18 November 2008

Workflow Extensions and Item Template for Debugging

A huge issue around workflows in general is tracing and error handling. When a workflow encounters an error it will simply state "Error Occurred" within the workflow status column. The data is then written to the SharePoint log file.

Previously, I was using the Unified Log Viewer from CodePlex which I do recommend, but at times I found it hard to get on a live server's central administration site to do this.

To get around this, I am writing the error information straight to the workflow history list.

I have also added a method to ensure that the automatically inserted workflow column gets removed, as this can confuse end users and can be added within a separate, non-default view.

Method for logging errors to history list:

   1: /// <summary>


   2: /// Logs a message to the history list of the workflow instance.


   3: /// </summary>


   4: /// <param name="workflowProperties">The <see cref="SPWorkflowActivationProperties"/> to extend this functionality to.</param>


   5: /// <param name="message">The message to log to the history list.</param>


   6: public static void LogToHistoryList(this SPWorkflowActivationProperties workflowProperties,


   7:                                     string message)


   8: {


   9:     try


  10:     {


  11:         workflowProperties.Workflow.CreateHistoryEvent(


  12:             0,


  13:             null,


  14:             null,


  15:             string.Empty,


  16:             message,


  17:             string.Empty);


  18:     }


  19:     catch


  20:     {


  21:         return;


  22:     }


  23: }




Method for removing status column:





   1: /// <summary>


   2: /// Removes the workflow status column from the default view.


   3: /// </summary>


   4: /// <param name="workflow">The activity to extend this functionality to.</param>


   5: /// <param name="properties">The <see cref="SPWorkflowActivationProperties"/> from the workflow instance.</param>


   6: public static void RemoveStatusColumn(this Activity workflow,


   7:                                       SPWorkflowActivationProperties properties)


   8: {


   9:     using (SPSite site = new SPSite(properties.SiteId))


  10:     {


  11:         using (SPWeb web = site.OpenWeb(properties.WebId))


  12:         {


  13:             SPList list = web.Lists[properties.ListId];


  14:             SPView view = list.DefaultView;


  15:  


  16:             SPField field = list.Fields[properties.TemplateName];


  17:             field.Hidden = true;


  18:             field.Update();


  19:  


  20:             try


  21:             {


  22:                 view.ViewFields.Delete(field);


  23:                 view.Update();


  24:                 list.Update();


  25:                 properties.LogToHistoryList(


  26:                   "Workflow status column removed from default view on list.");


  27:             }


  28:             catch (SPException)


  29:             {


  30:                 //Does not exist.


  31:                 return;


  32:             }


  33:         }


  34:     }


  35: }




If anyone knows of a better way of checking if the field exists already (the field name is completely random) then please let me know as this would be far better than letting the code throw an error on line 22. I have created an item template for Visual Studio 2008 that includes refactored, commented code and uses the two methods mentioned above.



Download the template and extension class.

SharePoint Workflow Debugging "gotchas"

The workflow templates that come with the SharePoint 2007 SDK have a good few issues.

Some of the "gotchas" around deployment and debugging include:

  • To get the project wizard to work, the SharePoint site that you connect to must contain
    • a task list
    • a document library
  • You need dbowner rights or equivalent directly on the SharePoint content database
  • A copy of your feature.xml and workflow.xml has to remain inside the workflow project for use by the auto deployment
  • The template properties wizard must complete successfully to create the debug deployment settings
    • To rerun the wizard, select the project and the properties pane will show the wizard settings. Editing any of these reruns the wizard
  • You need to be a site collection administrator on the site

16 November 2008

Extended Lookup Field for SharePoint

I am currently working on an open source project on CodePlex named "Extended Lookup", an extension of the lookup field type definition in Microsoft SharePoint 2007.

One problem with lookup fields are the limitation of using source lists within the same site, or SPWeb, and that the source data cannot be filtered. For example, you might want to create a lookup to a list within another site and this list might contain information that is not suitable for your list. In this case, you can create a view in that list that filters the results. You can then bind the lookup to this view in order to limit the lookup choices.

Currently, all coding and testing is complete for single lookups, but more work is needed for the multi lookup field, or "allow multiple values" lookup type.

The project will be released before christmas and will go to beta testing and peer feedback early December 2008.

Screenshot 1: Out-of-the-box lookup field



Screenshot 2: Extended lookup field in design mode


Tobias Lekman
Search this blog