Leaving the BDC Meta Man project

May 8th, 2007 by tbaginski

 

In order to pursue other opportunities, I've decided to end my involvement with the BDC Meta Man project.

For almost a year now I have been working on the BDC Meta Man project with Nick Swan and Dmitry Kaloshin.  During this exciting time I forged strong relationships with Nick and Dmitry and enjoyed the experience very much.  The entire experience was a positive one and I have nothing but good things to say about Nick and Dmitry.  I am confident that Nick and Dmitry will create an even brighter future for the project, and I wish them both luck!

Thanks to everyone who supported the BDC Meta Man project along the way, it was an exciting journey!  Now that I'm embarking on a new journey with SharePoint Experts as Vice President, stay tuned for some exciting announcements of my own!

SharePoint Connections – Session Follow Up: Create an Internet-Facing SharePoint Site

April 12th, 2007 by tbaginski

During the Create an Internet-Facing SharePoint Site session I covered the following topics.

  1. Setting up forms based authentication.
  2. Creating your own custom Master Pages and style sheets
  3. Personalizing site content for users.
  4. Leveraging the Business Data Catalog to surface and interact with back end systems.

Each of these topics is broken down more in depth in this blog post.  All the code used during my demos can be found in the rar file linked at the end of this post.

Setting up forms based authentication

Because a brief survey revealed almost the entire audience had already attended a session that covered setting up forms based authentication for SharePoint sites, I moved quickly through the materials related to setting up forms based authentication for SharePoint sites and did not spend a lot of time on it.

At any rate, here are the step by step instructions that describe how to set up a SharePoint site to use forms based authentication.

*Note:  There are also several GREAT blog posts that describe how to set up FBA with SharePoint sites available on the Internet as well.

Andrew Connell has a great article on this topic here:

HOWTO: Configuring a Office SharePoint Server 2007 Publishing Site with Dual Authentication Providers and Anonymous Access

Dan Attis also has two great articles on this topic here:

Office SharePoint Server 2007 – Forms Based Authentication (FBA) Walk-through – Part 1

Office SharePoint Server 2007 – Forms Based Authentication (FBA) w/MySites Walk-through – Part 2

Without further adieu, here are the step by step instructions.

Part 1: Create the database FBA will use to store credentials, roles, and users.

1. On your SharePoint development server open Windows Explorer.

2. Navigate to the following directory:

%windir%Microsoft.NETFrameworkv2.0.50727

3. Double click the aspnet_regsql.exe file to open the ASP.NET SQL Server Setup Wizard.

4. Click the Next button.

5. Make sure the Configure SQL Server for application services radio button is selected.

6. Click the Next button.

7. In the Server textbox enter the name of the SQL Server that will hold the database.

8. Make sure the Windows Authentication radio button is selected.

9. In the Database textbox enter SP_FBA_DB.

10. Click the Next button.

11. Click the Next button.

12. Click the Finish button.

Part 2: Configure the ASP.NET Membership and Role Providers to use the SP_FBA_DB database.

1. On your SharePoint development open VS 2005.

2. Click File | New | Web Site.

3. In the templates list box select ASP.NET Web Site.

4. In the Location drop down list, select File System.

5. In the Location text box enter:

c:inetpubwwwrootSP FBA Administration Site

6. Click the OK button.

7. When the Web Site is created, right click the c:…SP FBA Administration Site node in the Solution Explorer and select Add New Item.

8. In the Templates list box select Web Configuration File.

9. Click the Add button.

10. Locate the following code in the web.config file:

<connectionStrings/>

11. Replace the code above with the code below:

<connectionStrings>

<add

name="SP_FBA_DB_SQL_CONN_STRING"

connectionString="server=<Your SQL Server Name>

database=SP_FBA_DB;

Integrated Security=SSPI;"

providerName="System.Data.SqlClient"

/>

</connectionStrings>

12. Replace the <Your SQL Server Name> placeholder with the name of the SQL Server that you installed the database on, in Part 1.

13. Inside the <system.web> section in the web.config file, insert the following code.

<membership defaultProvider="SP_FBA_DB_AspNetSqlMembershipProvider">

<providers>

<add

name="SP_FBA_DB_AspNetSqlMembershipProvider"

type="System.Web.Security.SqlMembershipProvider,

System.Web,

Version=2.0.0.0, Culture=neutral,

PublicKeyToken=b03f5f7f11d50a3a"

connectionStringName="SP_FBA_DB_SQL_CONN_STRING"

enablePasswordRetrieval="false"

enablePasswordReset="true"

requiresQuestionAndAnswer="false"

applicationName="/"

requiresUniqueEmail="false"

passwordFormat="Hashed"

maxInvalidPasswordAttempts="5"

minRequiredPasswordLength="1"

minRequiredNonalphanumericCharacters="0"

passwordAttemptWindow="10"

passwordStrengthRegularExpression=""

/>

</providers>

</membership>

<roleManager

enabled="true"

defaultProvider="SP_FBA_DB_AspNetSqlRoleProvider">

<providers>

<add name="SP_FBA_DB_AspNetSqlRoleProvider"

type="System.Web.Security.SqlRoleProvider, System.Web,

Version=2.0.0.0, Culture=neutral,

PublicKeyToken=b03f5f7f11d50a3a"

connectionStringName="SP_FBA_DB_SQL_CONN_STRING"

applicationName="/"

/>

</providers>

</roleManager>

14. In VS 2005 Click Website | ASP.NET Configuration.

15. Click the Security link.

16. Click the Select authentication type link.

17. Select the From the internet radio button.

18. Click the Done button.

19. Don't close IE at this point, we will use it in the next part.

Part 3: Create a user to use for testing purposes.

1. Return to IE.

2. Click the create user link.

3. In the User Name text box enter: SP_FBA_DB_TEST_USER

4. In the Password text box enter: password

5. In the Confirm Password text box enter: password

6. In the E-Mail text box enter SP_FBA_DB_TEST_USER@test.com

7. Click the Create User button.

8. Click the Continue button.

9. Don't close IE at this point, we will use it again in just a bit.

Part 4: Verify all configuration settings.

1. Return to IE.

2. Click the Provider tab.

3. Click the Select a different provider for each feature (advanced) 4. link.

5. In the Membership Provider section, verify the SP_FBA_DB_AspNetSqlMembershipProvider radio button is selected.

6. Click the Test link next to the SP_FBA_DB_AspNetSqlMembershipProvider Membership Provider.

7. You should see the message: Successfully established a connection to the database.

8. Click the OK button.

9. In the Role Provider section, verify the SP_FBA_DB_AspNetSqlRoleProvider radio button is selected.

10. Click the Test link next to the SP_FBA_DB_AspNetSqlRoleProvider Role Provider.

11. You should see the message: Successfully established a connection to the database.

12. Click the OK button.

Part 5: Create a SharePoint Web Application that will utilize FBA.

Here, we will expose an existing SharePoint Web Application as an extranet site. Basically, we are exposing the same content to extranet users via a different URL, and using FBA to authenticate the users to the site, instead of Active Directory.

1. Open the SharePoint Central Administration web site.

2. Click Start | All Programs | Microsoft Office Server | SharePoint 3.0 Central Administration.

3. Click the Application Management link.

4. Click the Create or extend Web application link.

5. Click the Extend an existing Web application link.

6. In the Web Application drop down list, select Change Web Application.

7. In the Select Web Application popup window, click the default SharePoint Web Application. (SharePoint (80)).

8. In the Description text box enter SharePoint (80) – FBA

9. In the Port text box enter 80.

10. In the Host Header text box enter FBA

11. In the security Configuration section do the following:

12. Select NTLM as the Authentication Provider.

13. Set Anonymous Access to No.

14. Set Use Secure Sockets Layer (SSL) to No.

15. In the Load Balanced URL section change the Zone to Extranet.

16. Click the OK button.

Part 6: Configure FBA for the SharePoint Web Application created in Part 5.

1. Open Windows Explorer.

2. Navigate to the directory where the FBA SharePoint Web Application was created.

a. By default, this location will be:

C:InetpubwwwrootwssVirtualDirectoriesFBA80

3. Open the web.config file in this directory.

4. Locate the following code in the web.config file:

</SharePoint>

5. Add the following code below the line of code above.

<connectionStrings>

<add

name="SP_FBA_DB_SQL_CONN_STRING"

connectionString="server=<Your SQL Server Name>

database=SP_FBA_DB;

Integrated Security=SSPI;"

providerName="System.Data.SqlClient"

/>

</connectionStrings>

6. Replace the <Your SQL Server Name> placeholder with the name of the SQL Server that you installed the database on, in Exercise 1.

7. Locate the following code in the web.config file:

<system.web>

8. Add the following code below the line of code above.

<membership defaultProvider="SP_FBA_DB_AspNetSqlMembershipProvider">

<providers>

<add name="SP_FBA_DB_AspNetSqlMembershipProvider"

type="System.Web.Security.SqlMembershipProvider,

System.Web,

Version=2.0.0.0, Culture=neutral,

PublicKeyToken=b03f5f7f11d50a3a"

connectionStringName="SP_FBA_DB_SQL_CONN_STRING"

enablePasswordRetrieval="false"

enablePasswordReset="true"

requiresQuestionAndAnswer="false"

applicationName="/"

requiresUniqueEmail="false"

passwordFormat="Hashed"

maxInvalidPasswordAttempts="5"

minRequiredPasswordLength="1"

minRequiredNonalphanumericCharacters="0"

passwordAttemptWindow="10"

passwordStrengthRegularExpression=""

/>

</providers>

</membership>

<roleManager

enabled="true"

defaultProvider="SP_FBA_DB_AspNetSqlRoleProvider">

<providers>

<add name="SP_FBA_DB_AspNetSqlRoleProvider"

type="System.Web.Security.SqlRoleProvider, System.Web,

Version=2.0.0.0, Culture=neutral,

PublicKeyToken=b03f5f7f11d50a3a"

connectionStringName="SP_FBA_DB_SQL_CONN_STRING"

applicationName="/"

/>

</providers>

</roleManager>

Part 7: Configure SharePoint Central Administration so it can also communicate with the SP_FBA_DB database.

1. Open Windows Explorer.

2. Navigate to the directory where the SharePoint Central Administration web application was created.

3. By default, this location will be:

C:InetpubwwwrootwssVirtualDirectories<Your Port Here>

a. The <Your Port Here> placeholder is the port that SharePoint Central Administration uses on your server.

4. Open the web.config file in this directory.

5. Locate the following code in the web.config file:

</SharePoint>

6. Add the following code below the line of code above.

<connectionStrings>

<add

name="SP_FBA_DB_SQL_CONN_STRING"

connectionString="server=<Your SQL Server Name>

database=SP_FBA_DB;

Integrated Security=SSPI;"

providerName="System.Data.SqlClient"

/>

</connectionStrings>

7. Replace the <Your SQL Server Name> placeholder with the name of the SQL Server that you installed the database on, in Exercise 1.

8. Locate the following code in the web.config file:

<system.web>

9. Add the following code below the line of code above.

<membership defaultProvider="SP_FBA_DB_AspNetSqlMembershipProvider">

<providers>

<add name="SP_FBA_DB_AspNetSqlMembershipProvider"

type="System.Web.Security.SqlMembershipProvider,

System.Web,

Version=2.0.0.0, Culture=neutral,

PublicKeyToken=b03f5f7f11d50a3a"

connectionStringName="SP_FBA_DB_SQL_CONN_STRING"

enablePasswordRetrieval="false"

enablePasswordReset="true"

requiresQuestionAndAnswer="false"

applicationName="/"

requiresUniqueEmail="false"

passwordFormat="Hashed"

maxInvalidPasswordAttempts="5"

minRequiredPasswordLength="1"

minRequiredNonalphanumericCharacters="0"

passwordAttemptWindow="10"

passwordStrengthRegularExpression=""

/>

</providers>

</membership>

<roleManager

enabled="true"

defaultProvider="AspNetWindowsTokenRoleProvider">

<providers>

<add name="SP_FBA_DB_AspNetSqlRoleProvider"

type="System.Web.Security.SqlRoleProvider, System.Web,

Version=2.0.0.0, Culture=neutral,

PublicKeyToken=b03f5f7f11d50a3a"

connectionStringName="SP_FBA_DB_SQL_CONN_STRING"

applicationName="/"

/>

</providers>

</roleManager>

10. The only difference in the web.config entries for the Central Administration web site is as follows:

a. In the FBA SharePoint Web Application web.config file the roleManager tag looks like this:

<roleManager enabled="true" defaultProvider="SP_FBA_DB_AspNetSqlRoleProvider">

b. In the Central Administration web.config file the roleManager tag looks like this:

<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">

c. The differences are noted in bold.

Part 8: Adjust your hosts file so the FBA website will resolve properly.

1. Open Windows Explorer.

2. Navigate to the following directory:

3. %windir%system32driversetc

4. Open the hosts file.

5. Add the following line at the end of the file:

127.0.0.1 fba

6. Save the file.

Part 9: Turn on FBA for the FBA SharePoint Web Application created in Part 5.

1. Open the SharePoint Central Administration web site.

a. Click Start | All Programs | Microsoft Office Server | SharePoint 3.0 Central Administration.

2. Click the Application Management link.

3. Click the Authentication providers link.

4. Click the Extend an existing Web application link.

5. In the Web Application drop down list, select Change Web 7. Application.

6. In the Select Web Application popup window, click the default SharePoint Web Application. (SharePoint (80)).

7. When the page refreshes, click the Extranet link.

8. On the Edit Authentication page do the following.

a. Set Authentication Type to Forms.

b. Check the Enable anonymous access check box.

c. In the Membership provider name text box enter:

SP_FBA_DB_AspNetSqlMembershipProvider

d. In the Role manager name text box enter:

SP_FBA_DB_AspNetSqlRoleProvider

e. Select the no radio button under Enable Client Integration.

9. Click the Save button.

Part 10: Grant permissions to the SP_FBA_DB_TEST_USER test user you created in the SP_FBA_DB database, so they may access the SharePoint Site.

1. Open the SharePoint Central Administration web site.

a. Click Start | All Programs | Microsoft Office Server | SharePoint 3.0 Central Administration.

2. Click the Application Management link.

3. Click the Policy for Web application link.

4. In the Web Application dropdown select Change Web Application.

5. Click the SharePoint (80) link.

6. Click the Add Users button.

7. In the Zones drop down list select Extranet.

8. Click the Next > button.

9. In the Users text box enter the name of the test user created in Part 3.

a. The user name is: SP_FBA_DB_TEST_USER.

10. Click the Check Names button.

11. In the Choose Permissions section check the Full Control – Has full control. Check box.

12. Click the Finish button.

Part 11: Test the FBA by logging in with the test user.

1. Open IE.

2. Browse to the following url:

a. http://fba

3. You will be prompted with the FBA login page.

a. In the user name text box enter: SP_FBA_DB_TEST_USER

b. In the Password text box enter: password

4. Click the Sign In button.

Creating your own custom Master Pages and style sheets

In the rar file linked at the end of this post, you will find the Master Page and CSS files I used to create the demo site that looked like this.

Personalizing site content for users

In my session, both SharePoint Site Groups and custom Web Parts were used to personalize a user's experience.

To demonstrate how to personalize a user's experience within a custom Web Part I created a custom Web Part to surface ski report data via the BDC.  The custom Web Part I created to surface information from the BDC allowed users to specify which view of the data they would like to see.

Turning on the enhanced view of the custom Web Part looks like this:

Notice that some values are rendered in bold and in the color green when the enhanced view is turned on.  This helps you quickly determine which resorts you need to go shred!

Turning off the enhanced view of the custom Web Part looks like this:

The code inside the custom Web Part that made this personalization possible looks like this:

bool enhancedView;

[WebBrowsable(true),
Category("BDC Configuration"),
Personalizable(PersonalizationScope.User),
DefaultValue(true),
WebDisplayName("Display enhanced view"),
WebDescription("Toggles the way the data is presented.")]
public bool EnhancedView
{
get { return enhancedView; }
set { enhancedView = value; }
}

Notice the Personalizable attribute, in this case, is set to PersonalizationScope.User.  This specifies that the value of the property will be stored individually for each user who accesses the site.  This property value is stored in the SharePoint database.

The complete source code for this Web Part may be found in the rar file linked at the end of this post.

Leveraging the Business Data Catalog to surface and interact with back end systems

This portion of my presentation showed how to use the out of the box BDC Web Parts to surface data from back end systems in SharePoint sites secured via Windows Credentials with the Active Directory, as well as showing how to expose BDC data from within a SharePoint site secured via FBA.

The out of the box BDC Web Parts do not work in SharePoint sites secured via FBA.  So, in order to surface BDC data in a SharePoint site secured via FBA, I created a custom Web Part and Web Service to access the BDC data.

The complete source code for the custom Web Part class and the custom Web Service class used to surface BDC data within a SharePoint site secured via FBA may be found in the rar file linked at the end of this post.

As you will see below, returning data from the BDC requires many different steps to be taken.  Hopefully the comments I provided in the code sample below adequately describe how this process is accomplished.

The real nuts and bolts associated with returning data from the BDC looks like this.

[WebMethod]
public DataSet QueryBDC(string sharedResourceProviderName, string lobSystemInstanceName, string entityName)
{

//The DataTable the results from the BDC are stored in
DataTable dataTable = new DataTable("Resorts");

//The DataSet the Web Service returns
DataSet dataSet = new DataSet();

//Specify which SSP to use to access BDC data
SqlSessionProvider.Instance().SetSharedResourceProviderToUse(sharedResourceProviderName);

//Create a collection of all the LOB System Instances in the BDC
NamedLobSystemInstanceDictionary sysInstances = ApplicationRegistry.GetLobSystemInstances();

//Create an object representing the LobSystemInstance to return the data from
LobSystemInstance lobSystemInstance = sysInstances[lobSystemInstanceName];

//Create an object representing the Entity to return the data from
Entity bdcEntity = lobSystemInstance.GetEntities()[entityName];

//Create an object representing the MethodInstance to invoke on the Entity
MethodInstance methInst = bdcEntity .GetFinderMethodInstance();

//Create an object we can use to loop through the data returned
IEntityInstanceEnumerator bdcEntityInstanceEnumerator =
(IEntityInstanceEnumerator)bdcEntity.Execute(methInst,
lobSystemInstance);

//Create a collection of all the fields returned
FieldCollection fieldCollection = bdcEntity.GetFinderView().Fields;

//Loop through the collection to create the DataColumns in the DataTable that will hold the results
foreach (Field field in fieldCollection)
{

DataColumn dataColumn = new DataColumn(field.Name, Type.GetType(field.TypeDescriptor.TypeName));
dataTable.Columns.Add(dataColumn);

}

//Populate the DataTable with the data
while (bdcEntityInstanceEnumerator.MoveNext())
{

IEntityInstance iEntityInstance = bdcEntityInstanceEnumerator.Current;
DataRow dataRow = dataTable.NewRow();

foreach (Field field in bdcEntity.GetFinderView().Fields)
{

    if (iEntityInstance[field] != null)
    {

        dataRow[field.Name] = iEntityInstance[field];

    }

    dataTable.Rows.Add(dataRow);

}

}

//Add the DataTable to the DataSet
dataSet.Tables.Add(dataTable);

//Return the DataSet
return dataSet;

}

Here is a link to the rar file that contains all the code you will need to replicate the demos I created for my session.

/files/folders/tbaginski/entry23216.aspx

In the rar file you will also find the following items to help you recreate this solution.

1. SQL Script to create the TPG (Todd's Powder Guides) database and Resorts Table that holds the ski resort data.

2. A tab delimited text file containing the sample data I used in my demo.

3. The BDC Application Definition representing the Resorts Table in the TPG database.

*Note: Make sure you change the following line of XML in the BDC Application Definition to point to your database server before you import the Application Definition into the BDC.

<Property Name="RdbConnection Data Source" Type="System.String">YOUR DATABASE NAME GOES HERE</Property> 

SharePoint Connections – Sessions Follow Ups

April 12th, 2007 by tbaginski

Thanks to everyone who attended the sessions I presented at the SharePoint Connections conference in Orlando!  I had a great time at the conference, and met a lot of great people there as well.

The following blog posts will come after this one, to break down each topic, and describe the code I used in my demos at the conference.

  • Create an Internet-Facing SharePoint Site
  • Integrate Smart Client and Windows Forms Applications with SharePoint Sites and the Business Data Catalog
  • Use the Visual Studio Extensions for Windows SharePoint Services to Create Custom Site Definitions and a Whole Lot More!

Thanks again for attending my sessions!  I hope to see you again this Fall in Las Vegas at the next SharePoint Connections conference where I will be presenting the following sessions.

  • Getting the most out of the Business Data Catalog
  • Implementing the MOSS SSO service in real world situations
  • SharePoint Object Model / Web Services Kick Start

I'm also thrilled that I was selected to present the Post-Conference session in Las Vegas!  The post-conference session is titled:

Hands on training – SharePoint Development Bootcamp

During this post conference workshop I'll present/teach modules from my SharePoint Development Bootcamp.  Each module has a short slide presentation, followed by a quick demo, then a lab exercise.

Attendees will be provided with handouts for all of the modules covered.  Each handout includes the bullet points in the slides, complete with detailed notes, explanantions, and screenshots related to each bullet point on the slide.  Each handout also includes click by click lab instructions that describe how to accomplish the lab.  All code snippets and materials needed to complete each lab will also be provided.

Attendees may complete the hands on labs during this POST-CON event, and I will assist them during lab time.

The bottom line:  This is a bonafide day of interactive SharePoint development training, not just presentations.  I encourage all attendees to come armed with a SharePoint development environment to use during lab time at the post conference session!

HOW TO: Create a custom Windows Workflow Activity and make it available in SharePoint Designer

March 8th, 2007 by tbaginski

Recently we (SharePoint Experts) have been utilizing Workflows inside MOSS to automate many of our internal business processes. Last night, while trying to automate a process, Dustin let me know that the Send an Email Activity, available by default in SPD, does not allow you to specify a from email address. He asked me if I could create a custom Workflow Activity to send emails that would provide the ability to specify a from email address.

I looked at several examples on the Internet and inside the ECM Starter Kit and none of the materials I found online provide step by step instructions. This slowed down my development efforts and made me think that this topic would be an excellent blog post to help people out, so I'm typing it up to help everyone who may want to create a custom Windows Workflow Activity and make it available in SharePoint Designer.

I developed the C# code you will see in this blog post and Dustin was instrumental in helping me hook in the existing form that is utilized by the out of the box Send an Email Activity in SPD.

To begin, let's cover the components necessary to create a custom Windows Workflow Activity and make it available in SPD.

The main pieces of the puzzle are as follows:

  1. The assembly that contains the custom Workflow Activity class.
  2. The web.config file corresponding to the SharePoint Web Application on your server where the custom Workflow Activity will be used.
  3. The WSS.ACTIONS file on your SharePoint server that registers Workflow Actions with SPD.

The following instructions will create a custom Workflow Activity in VS 2005. The Activity takes several input parameters and sends an email based on the parameters. This Activity reuses the existing form that is utilized by the out of the box Send an Email Activity in SPD which provides the ability to look up users to populate the To and CC fields, as well as entering the Subject and Body for the email.

UPDATE: Fabian Mortiz has an excellent article that describes how to take my code sample and extend it to read lookup fields inside the body of the email.  You can find his article here:  http://weblogs.mysharepoint.de/fabianm/archive/2007/08/27/workflow-entwicklung-teil-2-e-mail-aktivit-t-mit-benutzerdefinierter-absenderadresse-f-r-den-sharepoint-designer.aspx 

Here is a list of the input parameters this custom Activity uses:

SMTPServerName – specifies which SMTP server will send the email.

FromEmailAddress – specifies who the email is from.

To – specifies who the email is sent to.

Subject – specifies the subject of the email.

Body – specifies the body of the email.

CC – specifies who will be copied on the email.

To create the assembly that contains the custom Workflow Activity class, perform the following steps.

  1. Open VS 2005.
  2. Click File| New | Project.
  3. In the Project Types tree select Workflow.
  4. In the Templates list box select Workflow Activity Library.
  5. In the Name text box enter Sample.ActivityLibrary.
  6. Click the OK button.

To create the class for the custom Workflow Activity, perform the following steps.

  1. In the Solution Explorer, right click the Sample.ActivityLibrary node.
  2. Select Add | Activity.
  3. In the Add New Item window, select Visual C# Project Items in the Categories tree.
  4. Select Activity in the Templates list box.
  5. In the Name text box enter CustomEmailActivity.cs.
  6. Click the Add button.
  7. In the Solution Explorer, right click the CustomEmailActivity.cs file and select View Code.
  8. Replace the contents of the class with the following code:

    using System;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Collections;
    using System.Diagnostics;
    using System.Drawing;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Design;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization;
    using System.Workflow.Runtime;
    using System.Workflow.Activities;
    using System.Workflow.Activities.Rules;

    namespace Sample.ActivityLibrary
    {
    /// <summary>
    /// This class deines a custom Windows Workflow Activity that sends emails
    /// </summary>
    public partial class CustomEmailActivity : Activity
    {

    //Create a variable to access the Event Log when errors need to be logged
    private EventLog _eventLog;

    #region DepedencyProperties for the Activity

    public static DependencyProperty BCCProperty = DependencyProperty.Register("BCC", typeof(ArrayList), typeof(CustomEmailActivity));
    public static DependencyProperty BodyProperty = DependencyProperty.Register("Body", typeof(string), typeof(CustomEmailActivity));
    public static DependencyProperty CCProperty = DependencyProperty.Register("CC", typeof(ArrayList), typeof(CustomEmailActivity));
    public static DependencyProperty SubjectProperty = DependencyProperty.Register("Subject", typeof(string), typeof(CustomEmailActivity));
    public static DependencyProperty ToProperty = DependencyProperty.Register("To", typeof(ArrayList), typeof(CustomEmailActivity));
    public static DependencyProperty FromEmailAddressProperty = DependencyProperty.Register("FromEmailAddress", typeof(string), typeof(CustomEmailActivity));
    public static DependencyProperty SMTPServerNameProperty = DependencyProperty.Register("SMTPServerName", typeof(string), typeof(CustomEmailActivity));

    #endregion

    #region Properties

    [ValidationOption(ValidationOption.Required)]
    public string FromEmailAddress
    {
    get
    {
    return (string)base.GetValue(FromEmailAddressProperty);
    }
    set
    {
    base.SetValue(FromEmailAddressProperty, value);
    }
    }

    [ValidationOption(ValidationOption.Required)]
    public string SMTPServerName
    {
    get
    {
    return (string)base.GetValue(SMTPServerNameProperty);
    }
    set
    {
    base.SetValue(SMTPServerNameProperty, value);
    }
    }

    [ValidationOption(ValidationOption.Optional)]
    public string Body
    {
    get
    {
    return (string)base.GetValue(BodyProperty);
    }
    set
    {
    base.SetValue(BodyProperty, value);
    }
    }

    [ValidationOption(ValidationOption.Optional)]
    public ArrayList CC
    {
    get
    {
    return (ArrayList)base.GetValue(CCProperty);
    }
    set
    {
    base.SetValue(CCProperty, value);
    }
    }

    [ValidationOption(ValidationOption.Required)]
    public string Subject
    {
    get
    {
    return (string)base.GetValue(SubjectProperty);
    }
    set
    {
    base.SetValue(SubjectProperty, value);
    }
    }

    [ValidationOption(ValidationOption.Required)]
    public ArrayList To
    {
    get
    {
    return (ArrayList)base.GetValue(ToProperty);
    }
    set
    {
    base.SetValue(ToProperty, value);
    }
    }

    #endregion

    #region Contructor

    public CustomEmailActivity()
    {
    InitializeComponent();
    }

    #endregion

    #region Overidden Methods

    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
    {
    //Set up the Event Logging object
    _eventLog = new EventLog("Workflow");
    _eventLog.Source = "SharePoint Workflow";

    try
    {
    //Send the email
    SendEmail();
    }
    finally
    {
    //Dispose of the Event Logging object
    _eventLog.Dispose();
    }

    //Indicate the activity has closed
    return ActivityExecutionStatus.Closed;
    }

    #endregion

    #region Private Methods

    private void SendEmail()
    {
    try
    {
    //Create a new object that will send the email
    System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
    //Create an object to specify the from address for the email
    System.Net.Mail.MailAddress fromAddress = new System.Net.Mail.MailAddress(FromEmailAddress);
    //Set the from email address on the message object
    msg.From = fromAddress;
    //Add the email addresses stored in the To property to the email message object
    for (int i = 0; i < To.Count; i++)
    {
    msg.To.Add(To[ i ].ToString());
    }
    //Add the email addresses stored in the CC property to the email message object
    for (int i = 0; i < CC.Count; i++)
    {
    msg.CC.Add(CC[ i ].ToString());
    }
    //Mark the message body as HTML
    msg.IsBodyHtml = true;
    //Populate the subject for the message
    msg.Subject = Subject;
    //Populate the body for the message
    msg.Body = Body;
    //Create an object to represent the mail server that will send the message
    System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient(SMTPServerName);
    //Set the credentials used to authenticate to the email server
    client.UseDefaultCredentials = true;
    //Send the message
    client.Send(msg);
    }
    catch (System.Exception Ex)
    {
    //Log exceptions in the Event Log
    _eventLog.WriteEntry("SMTP Server Name: " + SMTPServerName +
    Environment.NewLine +
    "From: " + FromEmailAddress +
    Environment.NewLine +
    "To: " + To +
    Environment.NewLine +
    "CC: " + CC +
    Environment.NewLine +
    "Subject: " + Subject +
    Environment.NewLine +
    "Body: " + Body +
    Environment.NewLine +
    "Error: " + Ex.InnerException.ToString()
    , EventLogEntryType.Information);
    }
    }

    #endregion

    }
    }

  9. Save the file.
  10. Click Build | Build Sample.ActivityLibrary.
  11. Finally, sign the assembly.
    1. Right click on the Sample.ActivityLibrary node in the Solution Explorer.
    2. Select Properties.
    3. Click the Signing tab.
    4. Check the Sign the assembly checkbox.
    5. In the Choose a strong name key file dropdown list select New.
    6. Name the key file Sample.ActivityLibrary.snk.
    7. Uncheck the Protect my key file with a password checkbox.
    8. Click the OK button.
  12. Build the Assembly.
  13. Obtain the PublicKeyToken for your assembly.
    1. Open a command prompt.
    2. Change to the output directory of your Sample.ActivityLibrary project.
    3. Issue the following command: sn -T Sample.ActivityLibrary.dll
    4. Copy the value returned, and paste it into the AssemblyInfo.cs file in the Sample.ActivityLibrary project.
      1. You will use this value later in the deployment process.
    5. Make sure you comment out the line, like this:

      //Public key token is <Your PublicKeyToken will appear here>

  14. Deploy the assembly to the GAC on your SharePoint Server.

To edit the web.config file on your SharePoint server so the Activity has permissions to execute, perform the following steps.

  1. Open the web.config file corresponding to the SharePoint Web Application on your server where the custom Workflow Activity will be used.
  2. Locate the <authorizedTypes> section.
  3. Add the following XML inside the <authorizedTypes> section:

    <authorizedType Assembly="Sample.ActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<Insert Your PublicKeyToken Here> " Namespace="Sample.ActivityLibrary" TypeName="*" Authorized="True" />

  4. Return to your AssemblyInfo.cs file.
  5. Copy the Public Key Token you added to the class.
  6. Return to the web.config file.
  7. Replace the <Insert Your PublicKeyToken Here> placeholder with the value you copied from the web.config file.
  8. Save the web.config file.

To edit the WSS.ACTIONS file on your SharePoint server register the custom Activity with SPD, perform the following steps.

  1. Open the WSS.ACTIONS file on your SharePoint server.
    1. The file is located in the following directory:

    C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATE1033Workflow

  2. Locate the <Actions> section.
  3. Add the following XML inside the <Actions> section.
  4. <Action Name="Custom Email Action"
    ClassName="Sample.ActivityLibrary.CustomEmailActivity"
    Assembly="Sample.ActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9fed0241ddc0b7ef"
    AppliesTo="all"
    Category="Sample"> 
        <RuleDesigner Sentence="Send %1 from %2 via SMTP host %3."> 
            <FieldBind Field="To,CC,Subject,Body" Text="this message" DesignerType="Email" Id="1"/> 
            <FieldBind Field="FromEmailAddress" Text="this address" Id="2" DesignerType="TextArea"/> 
            <FieldBind Field="SMTPServerName" Text="SMTP Server" Id="3" DesignerType="TextArea"/> 
        </RuleDesigner> 
        <Parameters> 
            <Parameter Name="To" Type="System.Collections.ArrayList, mscorlib" Direction="In" /> 
            <Parameter Name="CC" Type="System.Collections.ArrayList, mscorlib" Direction="Optional" /> 
            <Parameter Name="Subject" Type="System.String, mscorlib" Direction="In" /> 
            <Parameter Name="Body" Type="System.String, mscorlib" Direction="Optional" /> 
            <Parameter Name="FromEmailAddress" Type="System.String, mscorlib" Direction="In" /> 
            <Parameter Name="SMTPServerName" Type="System.String, mscorlib" Direction="In" InitialValue="127.0.0.1" /> 
        </Parameters>
    </Action>

  5. Save the file.
  6. Reset IIS.

So what does this XML do? Let me explain.

The Action element specifies how the Activity will appear and be categorized when you click the Add button in SPD to add an Activity to a Workflow. The Action element also specifies what assembly and class the Action is contained in.

The RuleDesigner element specifies the text and links displayed in SPD once the Activity has been added to a Workflow in SPD.

The FieldBind elements inside the RuleDesigner element map the input controls to the Parameter elements defined in the Parameters element. Their IDs correspond to the %# arguments in the Sentence attribute inside the RuleDesigner element. The Text attributes correspond to the links displayed in SPD. The DesignerType attributes correspond to the type of control that will be used for input.

Note:

Notice the following line of XML is used to map multiple properties to the out of the box form that comes with the Send an Email Action. This is how we were able to reuse that form!

<FieldBind Field="To,CC,Subject,Body" Text="this message" DesignerType="Email" Id="1"/>

The Parameter elements map the properties of the custom Workflow Action to the properties defined in the class that represents the custom Workflow Activity. The Name attributes must match the names of the properties defined in the class that represents the custom Workflow Activity. The Type attributes must match the types of the properties defined in the class that represents the custom Workflow Activity.

To test the activity, perform the following steps. These steps will create a simple workflow and deploy it to the Announcements list in a Team Site.

  1. Create a Team Site on your SharePoint Server.
  2. Open SharePoint Designer.
  3. Click File | Open Site.
  4. In the Site name text box, type in the URL to the Team Site you just created.
  5. Click the Open button.
  6. Click File | New | Workflow.
  7. In the Give a name to this workflow text box enter: Custom Email Action Test Workflow.
  8. Click the Next button.
  9. Click the Actions button and select More Actions.
  10. In the Select a Category drop down list select Sample.
  11. Highlight Custom Email Action in the Choose an Action list box.
  12. Click the Add button.
  13. The Custom Email Action then appears in SPD, it looks like this:

  14. Next, click the 'this message' link.
  15. The out of the box form that comes with the Send an Email Activity will appear since we are reusing it. It looks like this after you populate it with values.

  16. Click the OK button when you are finished filling out the form.
  17. Next click the 'this address' link and type in who the email is from.
  18. Finally, click the '127.0.0.1' link and type in the name of your mail server if it is different from your SharePoint server.
  19. When you are finished specifying parameters, SPD looks like this (Note: you screen will look different when you use different parameters.):

  20. Click the Finish button.
  21. Open IE and navigate to the Team Site you created in step 1 above.
  22. Click the Announcements link.
  23. Mouse over the Get Started with Windows SharePoint Services! List Item.
  24. Right click the arrow that appears and select Workflows in the drop down menu.
  25. Select the Custom Email Action Test Workflow you just created by clicking on the hyperlink.
  26. When the page refreshes, click the Start button to start the workflow.
  27. When the page refreshes you will see the Custom Email Action Test Workflow has completed.
  28. The page will look like this:

Victory!  Well done, you just created a custom Windos Workflow Activity, registered it with SPD, and used it inside a SharePoint Workflow! 

NOTES:

  1. If sending the email fails, you will notice the status will be set to 'Completed' inside the List the workflow has been assigned to. This is because I did not return any failure information to SharePoint when an exception occurred while trying to send the email, since I am trying to keep this example simple.
  2. To see diagnostic information related to the Workflow, look in the Event Logs.
    1. To demonstrate the Event Logging built into the custom Activity, I configured my mail server to deny relaying to show you an example of the information logged in the Event Log when an Exception occurs.  This is what it looks like:

    1. As you can see, the email was not sent due to the relaying permissions set on my development server.
  3. Another thing that this custom Workflow Activity does not implement is validation of user input, so you'll need to add that on your own.
    1. For example, if you enter an invalid email address, like "user", instead of users@user.com, the .NET objects that send email will fail.

 

SharePoint Feature Manager – Updated Version Now Available

March 5th, 2007 by tbaginski

Today I updated the SharePoint Feature Manager based on feedback I have received about the application. 

The status text box now automatically scrolls after each operation is completed.  This should make the program easier to use.

You can download it here: /files/folders/tbaginski/entry2449.aspx

RTW of WSS and Office SharePoint Server Standard and Enterprise Evaluation Can Now Be Downloaded

November 16th, 2006 by tbaginski

Looking for the final bits to WSS 3.0 and Office SharePoint Server 2007?

Check out Joel's blog for all the details!

Announcing the RTW of WSS and Office SharePoint Server 2007 Standard and Enterprise Evaluation!

I polled a couple of celebrities to see what their thoughts were when they heard the news.

First, I called John Madden on the Madden Bus.  When I told him the news he said, 'You know, about halfway through the preseason you start thinking to yourself that you're ready for the season to begin… and then BOOOOM!  The season is upon you!'


Next, even though I didn't have a problem, and no one else could help, I decided to give Hannibal Smith a ring.  All Smith had to say was, 'I love it when a plan comes together!'

 

HOW TO: Prevent creation of sub sites within MOSS 2007 My Sites

November 14th, 2006 by tbaginski

What do you do to prevent your users from creating sub sites under their My Sites if you need to do so? Since there is not a way to shut down this ability from the Central Administration site you'll need to use some custom code to get the job done. The cool part is, I already wrote it for you. The solution I have created is very simple and leaves a very small footprint in your SharePoint environment, so it's easy to roll back to return your environment to a supportable state, or install future Service Packs.

The solution I've created consists of a Server Control and a custom aspx page. The Server Control is placed on the newsbweb.aspx page that is used to create SharePoint sites from a web browser.  The Server Control looks at the URL of the page being requested to determine if the request was made from a My Site.  If the Server Control finds that the request was initiated from a My Site it redirects the user to the custom ASPX page that lets them know they cannot create a sub site under a My Site.  The page has a link to return to the My Site, and it looks just like the other SharePoint pages because it uses the same application.master file.  If you change application.master the look and feel of the custom ASPX page will change along with all the other pages in the layouts directory.

You can download the VS.NET 2005 solution containing the code for the Server Control and the custom aspx page here.

To implement the solution follow these steps:

  1. Load the VS.NET 2005 solution named Custom.SharePoint.WebControls and build it.
  2. Copy the Custom.SharePoint.WebControls.dll file to the bin directory corresponding to the web site serving up your My Sites.
    1. For example, the My Site for the administrator on my development machine has a URL like this:
      http://moss-b2:30250/personal/administrator/default.aspx
    2. Therefore, the corresponding path on the file system to the bin directory for this web site looks like this:
      C:InetpubwwwrootwssVirtualDirectories30250in
  3. Next, edit the web.config file corresponding to the web site serving up your my Sites and add the SafeControl entry to register the assembly with SharePoint.
    1. You will find the SafeControl tag at the end of the AssemblyInfo.cs file in the Custom.SharePoint.WebControls project.
      1. It looks like this:
        <SafeControl Assembly="Custom.SharePoint.WebControls,Version=1.0.0.0,Culture=neutral" Namespace="Custom.SharePoint.WebControls" TypeName="*" Safe="True" />
      2. Copy and paste this value into the SafeControls section in the web.config file.
      3. Save the web.config file.
  4. Put the CanNotCreateMySiteSubSite.aspx file into the following directory on your SharePoint server:
    C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATELAYOUTS
  5. Make a backup of your existing newsbweb.aspx file which you will find in the following directory on your SharePoint server:
    C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATELAYOUTS
  6. Finally, copy the newsbweb.aspx file into the following directory on your SharePoint server:
    C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATELAYOUTS

To test the solution, perform the following steps:

Open IE and navigate to your my Site.
Click Site Actions
Click Create
Click Sites and Workspaces
Notice the following page appears

That's all there is to it.

SharePoint Connections – Sessions Follow Up

November 14th, 2006 by tbaginski

First of all I would like to say THANK YOU to everyone who came to my sessions last week! I had a wonderful time presenting my sessions to some great audiences and I really enjoyed meeting so many people after the sessions were over. I also enjoyed meeting many of the presenters and SharePoint MVPs at the conference. It was really nice to finally meet some of the folks who I have traded emails with for such a long time.

As I mentioned during the sessions, I'm following up on outstanding questions and comments in this post. I've broken down the information by session, so it is easier to locate.

HDV316: Integrating Applications with SharePoint – Without Writing a Line of Code!

Question: What Web Services are supported by the BDC?

Answer: The following information was taken from this article.

Business Data Catalog supports only "first" generation Web services. Therefore, if you are using Windows Communication Foundation Web Services, make sure you are using only WS-I Basic Profile v1.0. Business Data Catalog does not support the eight other binding choices that Windows Communication Foundation offers. For a sample, see the SampleWebService.

 

When you use Web services with overloaded methods, you cannot have multiple methods named identically in the Business Data Catalog metadata. A given entity can use only a single Web proxy method override at a given time. However, you can have multiple methods with the same name in the Web service. The Business Data Catalog will pick the correct method based on the signature in the metadata.

HDV419: Master Pages vs. Page Layouts (Types) in WSS V3

CODE: I've packaged several pages into a zip file you can find here.

This zip file contains the following:

  • Baseline.master – a minimal Master Page that you can use to build master pages to replace default.master.
  • CustomLayout.aspx – a customized Page Layout that began as the defaultLayout.aspx page which is the home page of the Publishing Portal template. The page has been customized to use a single Web Part Zone to display Web Parts.
  • CustomContentPages directory – contains two custom Content Pages and a Feature to install them.

STEP BY STEP INSTRUCTIONS TO USE THE FILES:

Making a new minimal Master Page and applying it to a site.

Navigate to a SharePoint Team site in IE.
Click Site Actions
Click Site Settings
Under the Galleries section, click Master Pages
Click Upload
Upload the Baseline.Master file

There are two ways to apply the page to the site:

  1. Here is a really cool Feature that installs a Web Part that allows you to pick the master page for a SharePoint site. Download this Feature, install it on your SharePoint Server, and then use it to set the Master Page.
  2. Open your site in SharePoint Designer, open the Master Page gallery node, select the Baseline.Master file, right click it and select Set as Default Master Page.

Installing and Activating the Custom Content Pages Feature.

Download the SharePoint Feature Manager Application from my blog
Copy the CustomContentPages directory in the zip file described above to the following folder on your SharePoint server: C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATEFEATURES
Run the SharePoint Feature Manager Application
Type in a URL for a SharePoint site where you want to Install and Activate the new Content Pages (Ex: http://sever/sitedirectory/teamsite)
Click the Browse button
Open the CustomContentPages directory, and select the Feature.xml file
Click the Open button
In the Operation dropdown select Install
Click Compose
Click Execute
In the Operation dropdown select Activate
Click Compose
Click Execute
Copy the URL you typed in and paste it into IE, then add the names of the custom Content Pages named example.aspx and example2.aspx. (Ex: http://sever/sitedirectory/teamsite/example.aspx & http://sever/sitedirectory/teamsite/example2.aspx)

Installing an configuring a new custom Page Layout to replace the home page of the portal

Open IE and navigate to the home page of your Portal
Click Site Actions
Click Site Settings
Click Modify All Site Settings
Click Master pages and page layouts
Click Upload
Click Browse and locate the customLayout.aspx file in the zip file described above
Click OK to upload the file
On the subsequent web page enter Custom Page Layout in the Title text box
In the Content Type Group dropdown list select Page Layout Content Types
In the Content Type Name select Welcome Page
Click the Check In button
On the subsequent web page locate the customLayout.aspx, click the dropdown arrow next to it and select Publish a Major Version
Click OK

To change the home page of the portal to use the custom Page Layout perform the following steps:

Click Site Actions
Click Edit Page
Click the dropdown next to the Page link, and select Page Settings and Schedule
In the Page Layout dropdown list select (Welcome Page) Custom Page Layout
Click the OK button
Click the dropdown next to the Page link, and select Check In.
Click the OK button
Click the Publish button

To create a new page with the custom Page Layout perform the following steps:

Click Site Actions
Click Create Page
In the Title text box enter Custom Welcome Page
In the URL name textbox enter CustomWelcomePage
In the Page Layout list box select (Welcome Page) Custom Page Layout
Click the Create button
The subsequent web page will display the new custom Page Layout you created.
Click the dropdown next to the Page link, and select Check In.
Click the OK button
Click the Publish button

HDV218: Microsoft Office InfoPath 2007 Enhancements

One of the questions in this session was about submitting the same InfoPath Form from different Form Libraries to a common location. Andy researched the topic some more after the session and found this article which describes how to do it. Thanks Andy!

HDV317: SharePoint v3, Office 12, and Workflows, Oh My!

I mistakenly stated that the four out of the box workflows (Approval, Collect Feedback, Collect Signatures, and Disposition Approval) are available in Windows SharePoint Services 3.0 (WSS). They're not, they are only available in Microsoft Office SharePoint Server 2007 (MOSS) – however you can easily create them in WSS.

Thanks again for coming to my sessions everyone!

I'm a SharePoint MVP!

October 5th, 2006 by tbaginski

On Sunday I found out that I've been granted the SharePoint Portal Server MVP Award!

I'd like to say thank you to everyone who helped me attain this award, it would not have been possible without your help. I'm honored to join this community, and look forward to working with the other MVPs.

Since we are on the MVP topic, I have finally found a way to work another one of my passions, sports, into my SharePoint Blog.

I'm so inspired by the award, that I'd like to take a moment to honor some of my all time favorite professional sports MVPs by posting their pictures.

Gary Gait
Philadelphia Wings
Baltimore Thunder
Colorado Mammoth
1995-1998, 2004
National Lacrosse League MVP


 

Claude Lemieux
New Jersey Devils
1995 Conn Smythe Trophy

Scott Stevens
New Jersey Devils
2000 Conn Smythe Trophy

 

Ken Anderson
Cincinnati Bengals
1981 NFL MVP

Brett Favre
Green Bay Packers
1995, 1996, 1997 NFL MVP

Barry Larkin
Cincinnati Reds
1995 MLB MVP

 

Pete Rose
Cincinnati Reds
1973 MLB MVP

   

Ski lifts open in 16 days!  Are your skis waxed yet?

MOSS 2007 B2TR Virtual Development Environments. To MS or VM: That is the question

September 20th, 2006 by tbaginski

To MS, or VM: that is the question:
Whether 'tis nobler in the mind to shell out the cash for extra memory and an external hard disk,
Or to take your desktop and turn it into a development server, and by doing so save money.

Wow, I believe my high school teacher who taught me about Hamlet will retract my diploma if he ever reads this.

This post is not actually about Hamlet, it's about choosing a virtualization technology. Now that MS and VMWare both offer free virtualization products, developers have two options to choose from when it comes to virtual development environments.

On the Internet you can find many blog posts and articles about how these two technologies stack up in relation to one another. All the benchmarks I have found on the Internet show the results of programs like SiSoftware Sandra, or other system benchmarking utilities. However, I have not found any benchmarks specifically geared to MOSS 2007 development, and the tasks performed during development.

So, I put on my Don King afro and acted like a fight promoter to set up a battle between the two technologies. The battle would be played by my rules, so I could learn first-hand which technology is better suited to host a virtual SharePoint development environment.

First, a little disclaimer. I am not being paid to write this article. I don't have a vendetta against either company. The results I am posting here may vary depending on your hardware setup. Etc.

Bottom line: I performed this analysis because I wanted to determine which technology was faster.

The benchmarks I am posting here reflect the day to day activities of a SharePoint developer. I tried to pick common tasks to benchmark, not minutia.

The contenders (Rocky vs. Apollo would be a lot more exciting, but they are way to cool to play with computers!):

MS Virtual Server 2005 R2 Enterprise Edition vs. VMWare Server 1.0.1

To level the playing field I started with a MS VPC virtual development environment and converted it to the VMWare format. By doing this I was able to use identical virtual machines for the tests. I used the VMWare P2V Assistant 2.1.1 to convert the image. The image I converted is 11GB in size, and the conversion process took about 3 hours.

Virtualized development machine specifications (Guest Machine):

Windows 2003 Server R2 – Standard Edition
Domain Controller
Application Server
SQL Server 2005 – Standard Edition
MOSS 2007 B2TR
VS.NET 2005 Team Edition for Software Architects
SharePoint Designer B2TR
Office 2007 B2TR

Memory allocated to virtual machine: 850MB

The arena (Host Machine):

HP Pavilion ZD8000
P4 3.4 GHz HT Processor
2GB RAM
USB 2.0 External Hard Disk – 7200RPM 16MB Cache

Operating System: Windows XP Pro

The battle (The tasks were performed in identical and sequential order in both virtualization technologies.):

It's easy to see that VMWare wins the battle in the MOSS 2007 virtual development image benchmark battle.

Here's a cool chart to help you visualize the data a little better:

Now, let's start analyzing the data a bit to see what kind of impact this would have over the course of a MOSS 2007 developer's typical week, and month. I put together a chart to help demonstrate. Values in the following chart are expressed in seconds, unless otherwise noted.

After analyzing the data, it's easy to see that VMWare saves you a good amount of time – time you would have just spent sitting around and waiting for your computer.

You may be wondering how I came up with the numbers in the "# of times event occurs weekly" column, so I put together a little chart to explain why I used the numbers I did.

I don't know about you, but now I know which virtualization technology I plan to use for my SharePoint virtual development environment – the statistics speak for themselves.

According to the Bill Gates Wealth Index, Bill Gates earns $300.00 per second. So, if you were Bill Gates, the time you saved in a week with VMWare would be worth $400,800.00, and the time you saved in a month would be worth $1,603,200.00. Amazing statistics aren't they? It's kind of ironic that I put that statistic in here, because without Bill, this blog probably wouldn't exist, you wouldn't be interested in reading it, and most likely, and I'd be a ski patroller.

The ski lifts open in 31 days!