Sunday, July 30, 2006

Adding a 'Save site as template' Link to Site Settings in WSS v3/MOSS 2007 using a CustomAction Feature


In an earlier post, Shane Young mentioned that the "Save site as template" link is only available under the Look and Feel menu of Site Settings at the Top Level of the site collection in WSS v3/MOSS 2007 Beta 2.  For all subsites, Shane advises to append “_layouts/savetmpl.aspx” to the URL in order to get to the Save Site as Template page.

Shane surmises that the missing link will be corrected by Microsoft post Beta 2, but in the meantime this omission poses a basic opportunity for developers to work with the new Features framework of WSS v3.  A new custom feature could enable site administrators to add a ‘Save site as template’ link to the Site Settings page of any WSS v3 site.

The SaveSiteAsTemplate feature will consist of a Feature.xml and an Elements.xml file.  Feature.xml declares the Feature itself, and Elements.xml further defines the CustomAction for the Look and Feel menu on a Site Settings page.   To get started, create a folder named SaveSiteAsTemplate below the Features folder located at C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES on your WSS v3 server.  Create Feature.xml and Elements.xml from the code below and place each file in the SaveSiteAsTemplate folder you just created.

Feature.xml

<?xml version="1.0" encoding="utf-8" ?>

<Feature Id="DE98E72D-80FF-4031-88B0-2E4DEF6312C8"

       Title="Save Site As Template"

       Description="Adds a 'Save Site As Template' link to the Look and Feel menu in Site Settings."

       Version="1.0.0.0"

       Scope="Web"

       Hidden="FALSE"

       xmlns="http://schemas.microsoft.com/sharepoint/" >

       <ElementManifests>

               <ElementManifest Location="Elements.xml" />

       </ElementManifests>

</Feature>

Note the Scope attribute in the Feature element of Feature.xml.  Scope can be set to either Farm, WebApplication, Site or Web.  Also notice that the ElementManifest element points to Elements.xml.

Elements.xml

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

       <CustomAction

       Id="SPSolutions.SaveSiteAsTemplate"

       GroupId="Customization"

       Location="Microsoft.SharePoint.SiteSettings"

       Sequence="1000"

       Title="Save site as template">

               <UrlAction Url="_layouts/savetmpl.aspx"/>

       </CustomAction>

</Elements>

Setting the Location of the CustomAction to Microsoft.SharePoint.Settings and the GroupId to Customization is what decides where the link will be render in the UI. 

Next, install the feature into WSS v3 by using the stsadm tool.  Stsadm.exe is located in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN on your WSS v3 server.

stsadm -o installfeature -name SaveSiteAsTemplate

Finally, activate the new feature on your WSS Site by going to Site Settings > Site Features and clicking the Activate button for the new Save Site As Template feature. 

Activate

You should now see a “Save site as template” link under the Look and Feel menu of the Site Settings page.

 

New Link added by Feature

Categories: , , , , ,

Tuesday, July 11, 2006

SharePoint in Higher Education


We've had an ongoing consulting project with Central Michigan University for the past nine months. The project involved the design and development of a new student portal based on SPS 2003. CMU has had a homegrown portal for students, but it had become outdated and they wanted something that was more flexible and had more features. They also needed the portal to be the front door to a new SAP Campus Management System that has been under development for over a year.

The new CMU Student Portal launched last week. Here is a screen shot of the home page:



CMU has approximately 20,000 students that will be using the portal. One of the most exciting aspects of the design is that each student will get their very own My Site. Prior to the new portal, students did not have a single place on the CMU network where they could store all of their important documents. Each college/department had its own network storage and students could use those file shares as they were enrolled in courses for a given college/network.

Now, with My Sites, students will have one place to store their documents AND it is accessible from anywhere they can open up a browser and get on the Internet and authenticate to the CMU SharePoint servers. This will be a vast improvement over what they have had. Here is a screen shot of a CMU My Site:



Lots of folks from CMU and SharePoint Solutions worked very hard on this project: Eric Bellmore, Sarah Bendele, Shane Young, Mike Glisson, Tony Bierman, Scott Mayo, Kevin Pine and myself were all part of the team. Congratulations to everyone!

Thursday, July 06, 2006

Presenting 2 Sessions at SharePoint Advisor Summit Phoenix August 27 - 31, 2006


I will be presenting 2 sessions at SharePoint Advisor Summit Phoenix August 27 - 31, 2006.
I will be presenting on these topics:
In this session you'll get to know the new WSS features framework. Features are a new innovation added for developers in this latest version of WSS. Features allow you to define, package and deploy discreet units of functionality such as custom commands, page templates, lists, content types, event handlers and work flows. You'll see how to build a feature using XML and Collaborative Application Markup Language (CAML). You'll learn how to package, deploy and activate a feature that will add custom commands to WSS sites and the lists within them. You’ll also learn how to define the schemas for lists, document libraries and content types. Finally, you'll see how to create site definitions containing feature references, and how to deploy features and site definitions using the new WSS Solution packaging mechanism.
Learn how to get ASP.NET 2.0 Web Parts up and running on a Windows SharePoint Services 3 site. You'll get a quick web part primer, and then learn how to create persistent Web Part properties and control property value serialization through ASP.NET type converters. You'll see advanced Web Part techniques such as data-binding controls to WSS lists and implementing Web Part connections. You’ll get acquainted with the SharePoint Control Library including SPGridView, SPTreeView, and other field controls that will enable you to create web parts consistent with SharePoint’s look and feel. You’ll also get a look at creating forms in Windows SharePoint Services 3, including how to leverage ASP.NET control templates.
Please register for the summit here.

Using Validators to Verify User Input from a Web Part's Custom EditorPart


This article applies to the ASP.NET 2.0 Web Part Framework, Windows SharePoint Services v3 (WSS v3), and Microsoft Office SharePoint Server 2007 (MOSS 2007).

ASP.NET 2.0 input validation controls allow for client side verification of data and quickly inform the user of input errors before form data is posted back to the web server.  Using validators saves on server resources and provides the user with a richer, more responsive experience.  This article will illustrate how input validation controls can be leveraged in a web part’s custom EditorPart to validate user input of web part properties.  

For illustration, assume we have a Visual Studio 2005 web control library project which contains a very simple web part of type JustPrintAuthorWebPart who’s sole responsibility is to render a book author’s full name in a web part page.  A book author’s full name may consist of either two words e.g. ‘FirstName LastName’ or three words e.g. ‘FirstName Middle LastName’.  JustPrintAuthorWebPart has associated with it a custom EditorPart of type AuthorEditorPart who’s job is to accept user input of the author full name, validate the author full name, and apply changes back to JustPrintAuthorWebPart for rendering and serialization.

All told, the example web control library project (download from the link at the end of this article) looks this:

SPSolutionsDemoJuly072006

The JustPrintAuthorWebPart implementation is trivial, with only one property BookAuthor of type Author.

[WebBrowsable(true)]
[Personalizable(PersonalizationScope.User)]
[Bindable(true)]
[Category("Data")]
[DefaultValue(typeof(Author), "")]
[PersistenceMode(PersistenceMode.InnerProperty)]
public Author BookAuthor
{
    get { return m_author; }
    set { m_author = value; }
}

The complex data type Author has three properties FirstName, MiddleName and LastName.  In order to use a complex data type as a personalizable property in an ASP.NET 2.0 web part, there must also exists a type converter who’s sole job is to convert instances of type Author to type String and back again for the purpose of serialization and deserializaton. 

ASP.NET includes six validation controls RequiredFieldValidator, RangeValidator, CompareValidator, RegularExpressionValidator, CustomValidator and ValidationSummary.  The project’s implementation of AuthorEditorPart utilizes RequiredFieldValidator, RegularExpressionValidator and CustomValidator to verify user input of the book author’s full name.

SPSolutionsDemoJuly072006-editorpart

RequiredFieldValidator ensures that a null value cannot be entered by the user.

SPSolutionsDemoJuly072006-requiredvalidator

Implementation of RequiredFieldValidator takes place in the overidden CreateChildControls method of AuthorEditorPart.

// Required field validator
RequiredFieldValidator authorRequiredValidator =
  new RequiredFieldValidator();
authorRequiredValidator.ControlToValidate = m_txtAuthor.ClientID;
authorRequiredValidator.ErrorMessage = "Author's name cannot be blank";
authorRequiredValidator.Display = ValidatorDisplay.Dynamic;
authorRequiredValidator.Text = "<img src=\"/_layouts/images/CNSCA16.GIF\"/>";

RegularExpressionValidator makes sure that the user input comes only in the form of two words e.g. ‘FirstName LastName’ or three words e.g. ‘FirstName Middle LastName’.

SPSolutionsDemoJuly072006-regexvalidator

RegularExpressionValidator is also implemented in AuthorEditor’s CreateChildControls method.

// Format validator
RegularExpressionValidator authorRegexValidator =
  new RegularExpressionValidator();
authorRegexValidator.ControlToValidate = m_txtAuthor.ClientID;
authorRegexValidator.ErrorMessage =
  "Author's name must be in the form of 'First Last' or 'First Middle Last'.";
authorRegexValidator.Display = ValidatorDisplay.Dynamic;
authorRegexValidator.Text = "<img src=\"/_layouts/images/CNSCA16.GIF\"/>";
authorRegexValidator.ValidationExpression = @"^\w+\s\w+\s\w+$|^\w+\s\w+$" ;

The final validator used in AuthorEditor is a CustomValidator which acts to inform the user if a server side ArgumentExceptionError is thrown during  the process of converting the user input into an Author object for serialization.

SPSolutionsDemoJuly072006-customvalidator

The CustomValidator is actually used within a try/catch block in the ApplyChanges() method of AuthorEditor.  The logic of ApplyChanges saves the user’s input to JustPrintAuthorWebPart for rendering and serialization.  If the process of converting the user’s input String into an instance of type Author fails, then the CustomValidator’s IsValid property is set to false and the user is informed.  This pattern doesn’t save a trip to the server, but does provide the user with an informative message in a consistent manner.

public override bool ApplyChanges()
{
    EnsureChildControls();
    JustPrintAuthorWebPart part = WebPartToEdit as JustPrintAuthorWebPart;
    if (part != null)
    {
        // Set web part properties based on editor control values
        try
        {
            AuthorConverter converter = new AuthorConverter();
            part.BookAuthor = (Author)converter.ConvertFrom(m_txtAuthor.Text);
        }
        catch (ArgumentException ex)
        {
            m_authorValidator.ErrorMessage =
                string.Format("{0} {1}", ex.GetType().ToString(), ex.Message);
            m_authorValidator.Text =
                "<img src=\"/_layouts/images/CNSCA16.GIF\"/>";
            m_authorValidator.IsValid = false;
            throw ex;
        }
    }
    else
        return false
;

    return true;
}

The Visual Studio 2005 web part library project containg all code shown in this article can be downloaded in this zip archive.

Monday, July 03, 2006

Deploying Web Parts with Solution Packages in WSS v3/MOSS 2007


Back in the good ‘ol days of WSS v2 and SPS 2003, we deployed web parts in CAB files called wppacks.  While wppacks can still be used to distrubute web parts in WSS v3 and MOSS 2007, a more compelling method is now to deploy your custom web parts along with features, site definitions and other artifacts in a SharePoint solution package.

The manifest.xml for a SharePoint solution package that includes web parts might look something like this:

<?xml version="1.0" encoding="utf-8" ?>
<Solution SolutionId="1F693B5D-87CB-4509-83E7-8681E7B032A3"
    xmlns="http://schemas.microsoft.com/sharepoint/">
 
  <FeatureManifests>
    <FeatureManifest Location="SPSolutionsDemoFeature\Feature.xml"/>
  </FeatureManifests>

  <SiteDefinitionManifests>
    <SiteDefinitionManifest Location="SPSolutionsDemo">
      <WebTempFile Location="1033\xml\webtempspsolutionsdemo.xml"/>
    </SiteDefinitionManifest>
  </SiteDefinitionManifests>
 
  <TemplateFiles>
    <TemplateFile Location="ControlTemplates\SPSolutions\SPSolutions.Demo.MyUserControlTemplate.ascx"/>
    <TemplateFile Location="ControlTemplates\SPSolutions\SPSolutions.Demo.SimpleControlTemplate.ascx"/>
    <TemplateFile Location="Layouts\ClientQueryTest.aspx"/>
  </TemplateFiles>
 
  <Assemblies>
    <Assembly DeploymentTarget="WebApplication"
          Location="SPSolutions.Demo.WebParts.dll">
      <SafeControls>
        <SafeControl Assembly="SPSolutions.Demo.WebParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e9db3057acd9c0f6"
          Namespace="SPSolutions.Demo.WebParts"
          TypeName="*" Safe="True" />
      </SafeControls>
    </Assembly>
  </Assemblies>
 
</Solution> 

Note the <SafeControl> element within <Assemblies><Assembly>.  This same <SafeControl> element will be reflected within SharePoint’s web.config upon successful installation of the solution package. 

The deployable CAB file is built using a tried-and-true utility from Microsoft called makecab.exe.  Makecab has been around since most those smart, young kids at Microsoft still had running noses and can be downloaded as part of the Microsoft Cabinet Software Development Kit.  The command to create a CAB file takes a configuration file or “DDF” as a parameter and looks something like this:

makecab.exe /f package.ddf

The contents of the DDF file tell makecab how to contruct the CAB file.  An  example DDF file might look something like this:

;*** Sample Source Code MakeCAB Directive file example
;
.OPTION EXPLICIT ; Generate errors
.Set CabinetNameTemplate=SPSolutionsDemoPackage.cab   
.set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory
.Set CompressionType=MSZIP ;** All files are compressed in cabinet files
.Set UniqueFiles="OFF"
.Set Cabinet=on
.Set DiskDirectory1=Package
manifest.xml
Assemblies\SPSolutions.Demo.WebParts.dll
.Set DestinationDir=ControlTemplates\SPSolutions
ControlTemplates\SPSolutions\SPSolutions.Demo.MyUserControlTemplate.ascx
ControlTemplates\SPSolutions\SPSolutions.Demo.SimpleControlTemplate.ascx
.Set DestinationDir=Layouts
Layouts\ClientQueryTest.aspx
.Set DestinationDir=SPSolutionsDemoFeature
Features\SPSolutionsDemoFeature\Feature.xml
Features\SPSolutionsDemoFeature\Elements.xml
.Set DestinationDir=SPSolutionsDemo
SiteTemplates\SPSolutionsDemo\default.aspx
SiteTemplates\SPSolutionsDemo\defaultdws.aspx
SiteTemplates\SPSolutionsDemo\ONET.xml
.Set DestinationDir=1033\xml
1033\xml\webtempspsolutionsdemo.XML
;*** <the end>

Once the redistributable cab file is created, we can use the stsadm.exe tool (located in c:\program files\common files\microsoft shared\web server extensions\12\bin\) that comes with SharePoint to actually  deploy the solution package.  Deploying a solution package is a two-step process that first involves adding the package to SharePoint’s solution store like this:

stsadm -o addsolution -filename SPSolutionsDemoPackage.cab

And then deploying the solution to a particular scope like this:

stsadm -o deploysolution -name SPSolutionsDemoPackage.cab -local -url http://beta

Saturday, July 01, 2006

WSS v3 Development Pattern - Binding a SPGridView to a SPDataSource in C#


The WSS v3 development pattern below illustrates a simple example for binding a SPGridView object to a SPDataSource object.  The pattern assumes a member variable m_grid of type SPGridView has been declared in your web part.

[c#]

protected override void CreateChildControls()
{
  SPWeb web = SPContext.Current.Web;
  using (SPDataSource ds = new SPDataSource())
  {
    ds.List = 
      web.Lists[new Guid("FB0ADC39-3792-4FC7-949C-F033D0671691")];
    ds.DataSourceMode = SPDataSourceMode.List;
    ds.IncludeHidden = false;
    ds.Scope = SPViewScope.Recursive;

    m_grid = new SPGridView();
    m_grid.DataSource = ds;
    m_grid.AutoGenerateColumns = false;

    m_grid.Columns.Clear();

    BoundField t = new BoundField();
    t.DataField = "Title";
    t.HeaderText = "Title";
    m_grid.Columns.Add(t);

    BoundField b = new BoundField();
    b.DataField = "Body";
    b.HeaderText = "Body";    
    b.HtmlEncode = false;
    m_grid.Columns.Add(b);

    m_grid.DataBind();
  }
  Controls.Add(m_grid);
}

Here’s the ouput:

Bindingspdataview