Showing posts with label VSeWSS. Show all posts
Showing posts with label VSeWSS. Show all posts

Monday, 3 September 2007

VSeWSS 1.1. CTP - a look at the nuts and bolts

Regular readers of this blog will know that I've been a reasonably keen advocate of Microsoft's Visual Studio Extensions for Windows SharePoint Services (VSeWSS) for certain SharePoint development tasks. If you read more than a couple of SharePoint blogs, you won't have avoided the news that MS have just released version 1.1 of this tool, as announced here by Alex Malek over on the SharePoint Designer blog. At the time of writing, this is a CTP (Community Technology Preview) meaning it is pre-beta, so bugs can be expected. So today I wanted to run through the changes, so folks who aren't familiar with the tool or haven't had a chance to take a look themselves can quickly get a sense of what's in there.

In essence, VSeWSS helps by simplifying the process of developing Features for SharePoint - this approach is generally regarded as the way to do SharePoint development in such a way that assets can be more easily deployed to other environments. In previous articles, I detailed how to create and deploy lists and how to create and deploy web parts with VSeWSS. For me, these are probably the scenarios where VSeWSS comes in the most useful, though there definitely are others depending on how you work. However, the most common gripe of developers who used the tool was that since VSeWSS 1.0 regenerated Feature files with each change, it wasn't possible to manually amend the files. This was often necessary to add things not directly supported by the tool, such as Feature receivers.

So let's run through the different areas where the tool has been improved.


WSP View

The big change with this release is that it is now possible to amend Feature files in the development process. Instead of hiding the generation of these files behind the scenes, the tool now makes these bona fide VS project items which can be edited before the Solution package is built. Certainly auto-generation of the final files still happens (that's the point) and there are some files lurking which are needed to support the tool, but VSeWSS now does a good job in presenting to you what you can modify through the WSP View (View > Other windows > WSP View). This is shown below for a project with some different artifacts:



Some nice things which can be done here are that entire Features can be deleted with a single click (all files will be removed), and the Feature activation order can be changed. Toolbar buttons are provided which modify the sequence of FeatureManifest elements in the manifest.xml file.


Feature file editing

So the WSP View provides the mask onto the editable files, but I wanted to drill into why this is useful. Some examples would be:

  • ability to add Feature receivers to a particular Feature
  • ability to rename properties of the Solution package, e.g. to bring VSeWSS-generated Solutions into line with a naming convention
  • ability to refactor Feature elements into a single Feature. This can be useful because by default the tool will create a new Feature each time you use Project > Add new item > Some SharePoint item (e.g. Content type). Often you will want several Feature elements to comprise a single Feature rather than split over several Features.

Event receivers

VSeWSS 1.1 also provides some enhancements around event receivers (handlers for events raised by lists). Version 1.0 also provided some support in this area, but the main scenario was adding a list/item receiver at the time the list was being created (i.e. "create list with receiver"). Version 1.1 now makes it easy to add an event receiver to an existing list, which simplifies those scenarios.

My favorite improvement in this area however, has to go to event receivers on content types. This effectively means that the event-handler code travels with the content type - so your code will run on all lists the content type is associated with. This is interesting as I had no idea this was possible in the WSS 3.0 platform! So I did some digging. I haven't yet done any testing of the results, but what VSeWSS does to support this is add some custom attributes to a standard list event receiver. For those interested, these are defined in the SPDevTools namespace in a file which is added to your project (out of the way in the Properties folder, alongside AssemblyInfo.cs) by the tool. I've not yet worked out exactly what picks up these flags in the Feature activation process, but it's clear that standard list event receivers are actually being used as the generated class derives from SPListEventReceiver. The image below (click to enlarge) highlights the new attribute being applied which supports all this:




Web parts

This was where I thought VSeWSS was a winner, and it's good to see the support for web part deployment has been extended further still. With 1.1, a default web part definition file (.webpart) is now generated for you to edit before deployment to add custom property settings. This is useful, since it means that developers can avoid the "deploy web part, add to page, configure, export web part" process which is otherwise required to obtain a configured definition.


Performance

One of the first things VSeWSS 1.0 users will notice is that a full IISReset is no longer performed on each deployment. This was something of a pain with version 1.0, since it meant the "edit, deploy, get feedback" cycle took longer than was necessary. So having been used to the IISResets, personally I was pretty pleased to see the message below in the Visual Studio status bar during the first deployment!



 
What could be better
 

So those are the good bits, and it's a great step in the right direction. However I'd still like to see the following:

  • fully-featured Solution Generator. I didn't have time to look at this in detail, but the download page specifies that certain items still aren't covered. This ties in with what I remember Alex Malek saying at this year's Tech Ed, that this still wouldn't be "full fidelity".
  • ability to easily add a Feature receiver to a Feature I'm working with. I just want right-click > Add Receiver - this should generate the class and add the attributes to the Feature definition with default values, or perhaps infer the generated type.
  • ability to easily refactor Feature elements in Features, since I often don't want the default of a Feature per element
  • no GUIDs in Feature names (though apparently this will be sorted by final release)
  • ability to deploy a _layouts file (again, this should be there in final release)

On a "bigger picture" note, I'm reminded of a common view in the SharePoint community which made complete sense when I heard it first from Ted Pattison. Unlike .Net, where Microsoft has gone to great lengths to ensure the tools are in sync with the platform (same team [Scott Guthrie], same timeframe for development phase, same ship date), a different thing is happening with SharePoint. Effectively the tools are 18 months behind the platform, so SharePoint development can be pretty painful at the moment -  however, this shouldn't be taken as a reflection of the platform.

This release of VSeWSS should help though, and it'll be interesting to see what comes in the future.

The download link is http://www.microsoft.com/downloads/details.aspx?FamilyID=3e1dcccd-1cca-433a-bb4d-97b96bf7ab63&displaylang=en.

Sunday, 12 August 2007

Site definitions - custom code in the site creation process

This is the second article in a series of three, where I aim to show how to customize the site creation process (known as site provisioning) with your own API code. The full introduction and series contents can be found at http://sharepointnutsandbolts.blogspot.com/2007/07/article-series-custom-permissions-with.html. The example customization I'm using is as follows: any sites created with the definition should use a specific set of permissions, and not simply follow the default behavior of inheriting the parent site's permissions. Since this can't be done with a standard site definition (like many other things you might want to do), use of the API is required.

However, today the focus is less on the permission specifics of my example, and more on how generally to add your own code which runs in the site provisioning process. And the best thing is, it's actually very simple if you understand SharePoint Features.

There are many reasons why you might have cause to use the API in the site provisioning process. Essentially, if you can't find a way to do what you want using CAML schema in the onet.xml file, chances are you'll have to write code. Hence, it's almost easier to think of what you can do in the onet.xml file and reverse the list in order to work out scenarios which require code, but some examples which spring to mind anyhow are:

  • changing the custom master page of a site
  • creating a site column which gets it's data from a list (see my post on my Feature receiver which does this at Feature to create lookup fields on Codeplex)
  • adding custom unique permissions to a site (the example in this article series)
  • set a site property from any kind of dynamic lookup

In short, there are many scenarios.


Creating site definitions with VSeWSS

If you've ever created a site definition with Visual Studio Extensions for Windows SharePoint Services, you'll notice that the VS project it gives you contains a file called SiteProvisioning.cs. Inside is an event-handler method, where you can add your custom code which will execute when a site is created from the definition. The class looks like this:

namespace COB.Demos.SiteDefinition

{

    public partial class ProjectXSiteDefinition

    {

        /// <summary>

        ///  Define your own feature activation action code here

        /// </summary>

        public void OnActivated(SPFeatureReceiverProperties properties)

        {

            // my code here..

        }

    }

}

 

The plumbing behind all this is interesting. At first glance, the method signature looks like a Feature receiver, but it's actually not. However, examining the VS project (you'll need to build the project with F5 at least once to generate the files) reveals that VSeWSS has in fact created some Features in the background. These files can be found under the bin\Debug\solution folder in your VS project (hidden by default - you'll need to do a 'Show All Files' in Visual Studio Solution Explorer). If you do some more delving around to see exactly what VSeWSS is doing, you'll find the following:

  • 2 hidden Features have been created - 1 deploys the 'default.aspx' file, the other has no 'elements' file but is hooked up to a Feature receiver - this is a class in an assembly named the same as your VS project. If you check the GAC, you will indeed find this assembly there.
  • a line similar to the following has been added to the onet.xml file under the 'WebFeatures' element:

    <Feature ID="67b2507c-8822-41dc-b939-3d8f34b5ad13" />


    Notably, this is the ID of the Feature which is hooked up to the Feature receiver.
  • Using Reflector on the assembly containing the Feature receiver shows that the main event-handler method performs some processing and then calls into the OnActivated method shown above, i.e. the place where VSeWSS provides for you to add your own code to execute when sites are created. This code is actually contained in the SiteProvisioning.Internal.cs file within the VS project. (If you're curious as to what on earth all the code in here is doing, the answer as far as I can tell is nothing when site definitions are created with the VSeWSS project template. However, this code is also found when Solution Generator is used to extract a site definition - in that case there are some fixups which need to be done, and this is the code which is used.)

So in summary, VSeWSS creates a hidden Feature is added to the 'WebFeatures' section of the onet.xml so that it is automatically activated when the definition is used to create a web*. The Feature is hooked up to a Feature receiver which calls the OnActivated method where your custom code lives.

*(Note that if the definition is used to create a site definition, the root web is also created automatically so the Feature would also be activated then. Also note the feature needs to be already installed in the farm for it to be activated in this way).

What we can derive from this is that there's no 'special place' in the site provisioning process to inject custom code, but it can be accomplished by use of a Feature receiver. So if you don't want to use VSeWSS to create site definitions, this is the technique to use to add your custom code to the site creation process.

In terms of what that code might look like, a 'Hello World' example could be:

public void OnActivated(SPFeatureReceiverProperties properties)

{

     SPWeb currentWeb = null;

     SPSite currentSite = null;

     object oParent = properties.Feature.Parent;

 

     if (properties.Feature.Parent is SPWeb)

     {

         currentWeb = (SPWeb)oParent;

         currentSite = currentWeb.Site;

     }

     else

     {

         currentSite = (SPSite)oParent;

         currentWeb = currentSite.RootWeb;

     }

 

     currentWeb.Title = "Set from provisioning code at " +  DateTime.Now.ToString();

     currentWeb.Update();

}


Hopefully this illustrates that it's quite simple to write code which sets properties on sites created from the definition. Generally the SPWeb object is the entry point, and any property which can be modified can be modified using the API. So, this is a pretty powerful technique which can be used in many scenarios.

If you have this type of requirement, I'd definitely recommend using VSeWSS to simplify the process. It's certainly possible to hook everything up manually and package it into a Solution, but the tool does save a large amount of hassle. However as usual with VSeWSS, the price of this is some flexibility. As my sample code in the final article will show, it's sometimes useful to pass data into Features by using Feature properties, and this unfortunately is not supported by VSeWSS. So in case it's useful, the following link provides a zip file containing a Solution/Feature which uses the above technique, without using VSeWSS:

http://sharepointchris.googlepages.com/customcodewithsitedefinitions

In the next and final article, I'll cover the specifics of using the API to modify site permissions as sites are created. As is hopefully clear, this is in conjunction with the technique detailed here so the net result is that the specific permissions are set 'automatically', courtesy of the Feature which is automatically activated against a site when it is created.

Sunday, 5 August 2007

Creating, deploying and updating custom site definitions

This is the first article in a series of three where we'll discuss custom site definitions, and in particular how to run your own custom code in the site creation process. This technique is useful if you need to make any customizations using the API beyond what can normally be accomplished with a site definition. In my series (for the full series contents, see my introduction at http://sharepointnutsandbolts.blogspot.com/2007/07/article-series-custom-permissions-with.html), I use the example of creating a site definition with specific security permissions 'attached' - so that when any sites are created using the definition, specific permissions are applied which are different to those of the parent site (this is unlike the default, which is for new sites to inherit the parent site's permissions). More background can be found in the introductory article linked to earlier.

In this article we'll start with the site definition basics - I'll also supply the set of files used in this article in a link at the end. Fundamentally, a custom site definition is a template from which new SharePoint sites can be created. Customizations can be packaged into the definition, so that they are present automatically in sites created from the template. Consider the following about site definitions:

  • they are created by copying an existing (e.g. out-of-the-box) site definition and adding customizations
  • XML files (in particular the onet.xml file) specify what a site definition consist of (i.e. .aspx pages, images, web parts, functionality [in the form of SharePoint Features])
  • they provide a similar functionality to site templates (.stp files) - for a discussion of the differences between site definitions and site templates see http://msdn2.microsoft.com/en-us/library/aa979683.aspx
  • site definitions can be deployed using a SharePoint Solution package (.wsp file), so that files do not need to be manually copied to each web server in a SharePoint farm

The process for creating site definitions is well-documented in the WSS 3.0 SDK at http://msdn2.microsoft.com/en-us/library/ms454677.aspx, so I actually won't cover it here but would encourage you to follow the link. However I will quickly run through some of the key elements in the onet.xml file to go over what can be done with site definitions. For an example, let's take an extract of the onet.xml file for a publishing (note for clarity this is an extract only - a full version is available at the link at the end of the article):

<Configuration ID="0" Name="BLANKINTERNET">

  <SiteFeatures>

    <Feature ID="A392DA98-270B-4e85-9769-04C0FDE267AA">

      <!-- PublishingPrerequisites -->

    </Feature>

    <Feature ID="7C637B23-06C4-472d-9A9A-7C175762C5C4">

      <!-- ViewFormPagesLockDown -->

    </Feature>

    <Feature ID="F6924D36-2FA8-4f0b-B16D-06B7250180FA">

      <!-- Office SharePoint Server Publishing -->

    </Feature>

  </SiteFeatures>

  <WebFeatures>

    <Feature ID="00BFEA71-4EA5-48D4-A4AD-305CF7030140" > </Feature>

    <Feature ID="22A9EF51-737B-4ff2-9346-694633FE4416">

      <!-- Publishing -->

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

        <Property Key="ChromeMasterUrl" Value="~SiteCollection/_catalogs/masterpage/BlueBand.master"/>

        <Property Key="WelcomePageUrl" Value="$Resources:cmscore,List_Pages_UrlName;/default.aspx"/>

        <Property Key="PagesListUrl" Value=""/>

        <Property Key="AvailableWebTemplates" Value="*-ProjectX#0"/>

        <Property Key="AvailablePageLayouts" Value="ThreeColumnLayout.aspx"/>

        <Property Key="AlternateCssUrl" Value="" />

        <Property Key="SimplePublishing" Value="false" />

      </Properties>

    </Feature>

  </WebFeatures>

  <Modules>

    <Module Name="LoginPage" />

    <Module Name="Images" />

    <Module Name="Home" />

  </Modules>

</Configuration>


  • The Configuration element represents settings to be used with the selected definition, allowing groups of settings to be reused across definitions for flexibility
  • SiteFeatures /WebFeatures - specifies which Features should be automatically activated when the definition is used to create a site collection or child site respectively. This is key to our overall aim in this series of creating a site definition which applies custom unique permissions to sites created from it.
  • AvailableWebTemplates property of publishing feature - can be used to restrict which site definitions can be used to create child sites within sites created from this definition. This can be useful to prevent your content creators adding a team site onto your public-facing .com website for example. Here I'm specifying that only the 'ProjectX' definition with Configuration '0' can be used for child sites.
  • AvailablePageLayouts property of publishing feature - can be used to restrict which page layouts can be used within sites created from this definition. Again, this can be useful in controlling the look and feel of your website.
  • Modules - a module is a set of files to be automatically added when sites are created. Note it's also possible to specify which web parts should be added by default to a web part page by using the AllUsersWebPart element.


Deploying site definitions


What I really want to focus on however, is how site definitions can be packaged into a Solution to simplify deployment. This is typically most useful when deploying to multiple environments (e.g. test, staging, production) and/or deploying to a farm which consists of multiple SharePoint web servers. If you don't have this requirement, you may want to consider the simpler process of copying the XML files around manually, as detailed in the WSS SDK.

Before we start, let me highlight that Visual Studio Extensions for Windows SharePoint Services (VSeWSS) is a useful tool for creating and deploying custom site definitions, and I'd recommend looking into it for this requirement if you haven't already. However, I'm illustrating the 'manual' way here to hopefully provide an understanding of the nuts and bolts.

So, to package these files as a Solution manually, we follow the SDK instructions to get our customized onet.xml and webtemp*.xml files, but then place the files in a similar folder structure to the existing site definition files found under the 12 folder. I recommend creating a Visual Studio project as the best way to group these files (VSeWSS also follows this approach). This means you should end up with something looking like this:



Note we also have a .ddf file which is used with makecab.exe to build the Solution package - see my article on building and deploying Solution packages for details on the full process here. Effectively, we need to build the Solution by passing the .ddf file as a parameter to makecab.exe, and then run the STSADM -o addsolution and STSADM -o deploysolution commands to deploy to our target SharePoint site.

Once this is done, on the 'create site' screen we should see our new template appear:



Users can now use this definition to create sites which automatically have all the functionality and appearance we specified upfront. If we then need to deploy the definition to other environments, it's a simple case of copying the .wsp file there and running the STSADM commands. We are now well on our way to creating a site definition with custom permissions associated with it.

The set of files used in this article are at http://sharepointchris.googlepages.com/creatinganddeployingcustomsitedefinition

Updating existing site definitions


Finally, a quick note on updating definitions. Care needs to be taken here as often you will want to update files which are in use by sites already created with the definition - this can break things! Generally adding to a definition is OK, but modifying/deleting things can cause problems.

So a good technique is to copy the existing definition, add the updates and deploy for new sites to use, but also hide the earlier version so it cannot be used going forward. This is accomplished by removing the webtemp*.xml file from the TEMPLATE\\XML directory. Any sites already provisioned from the earlier version of the definition will continue to run fine, since you're leaving the actual definition (onet.xml etc.) intact over in TEMPLATE\SiteTemplates.

Remember also that new Features can be stapled to existing site definitions (affecting only new sites which are created, not existing ones), and this can be useful in avoiding having to update the site definition itself. See my article on Feature-stapling for more details.

So that's site definition basics. Next in the series - how to go beyond simple site definitions : add custom code which will execute when sites are created!

Friday, 2 March 2007

Creating lists with VSeWSS

This is the first article in a series aimed at explaining the process of creating a MOSS site using SharePoint features. For the full series contents, see my introduction.

Here, we'll look at creating SharePoint lists. For something so simple and core to SharePoint, they're surprisingly difficult to create as a feature. Fortunately Visual Studio extensions for WSS simplifies the process dramatically. If you've not come across this yet I'd recommend trying it - WseWSS is basically a huge help for some SharePoint development scenarios. The following articles are good background:-

Briefly, the process of creating a list in VSeWSS is as follows:

  1. Create a blank Visual Studio project. N.B. if you're actually creating a SharePoint site definition, you should select 'Team Site Definition' or 'Blank Site Definition', as WSeWSS will set you up with provisioning code which will execute whenever a site gets created from this definition.

  2. Select 'Add New Item' on the Project menu, then select 'List Definition' from the SharePoint section.

  3. Typically you should select 'Custom list' as the base list definition from the dropdown. Only select another choice if you're actually extending that list type and want to retain the original's columns. Assuming you want to create the actual list in addition to a list template (more on this later), check the 'Create an instance of this list' box. Note also the option to 'Add with event receiver' - this sets up code which which can be used to handle events on the list, for example when list items are added/edited/deleted.



  4. After clicking OK in the dialog, name your list appropriately. My recommendation would be to avoid spaces or other characters which might get encoded somewhere - the list will have a display name which you can be freer with.

    WSeWSS has now created several files in your VS project.




    We can see the following:-


    • some aspx files, the pages users will use to work with your list. Note these can be customised if you want to deviate from the standard behaviour.

    • instance.xml - this is the file to edit to add initial data to your list. Since this file is automatically linked to the appropriate schema, it's fairly straightforward to edit as VS will tell you the valid nodes as you type (shown below).

    • two .cs files containing method stubs for event handlers. These are ready for you to your implementation to.

    • schema.xml - this contains the CAML which dictates which content types the list stores, any custom views and also has references to the .aspx files we mentioned
  5. If you want to add default items to your list (and you probably do if you created an instance of it), you can edit the instance.xml file. This is made simple because VSeWSS has hooked up instance.xml to the appropriate XML schema (C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\XML\wss.xsd), and you can then take advantage of VS's Intellisense which is inferred from the schema as you type:-



  6. After making any customisations such as editing instance.xml to add list items, go to the properties of your VS project and examine the 'SharePoint Solution' tab. Here you'll see VSeWSS has generated two features for each list. One is for the list instance, the other is for the list template. This can be used by users to create new lists on the site, using the columns you've defined.

  7. Go to the 'Debug' tab on the project properties, and enter the URL of your SharePoint development site. The solution will be deployed to this URL so it's important this value is entered.

  8. Hit F5 and WSeWSS will create and deploy the solution. Note that the .wsp file gets generated in the bin\Debug or bin\Release directory of your project. Keep an eye on the VS status bar in the bottom left to monitor progress. If the deploy succeeded, your list should now be visible in the site specified on the 'Debug' tab.


To anyone who has created SharePoint solutions/features by hand, VSeWSS offers a compelling alternative. No messing around with ddf files and makecab.exe, just hit F5. However, there are a couple of irritations:-

  • Since VSeWSS rewrites the feature.xml file on each deploy, there's no way to customise this file to add something which can't be entered on the 'SharePoint Solutions' area of the project properties. The major example is a feature receiver class to specify code which should run when the feature is activated/deactivated, should you want to do something here. Of course, you could edit the file at the end of the development cycle, but you know damn well there's always further tweaks and re-pasting the XML into feature.xml gets tiresome.

  • VSeWSS recreates the feature GUIDs on each deployment. This is great for development, but means you cannot have other features with feature dependencies on your list features. This can be a pain if you're trying to create a feature hierarchy or rationalise your features so that activating one will activate all required features for a given part of your solution.

Nevertheless, you now have your solution with a feature for each list you added. Well actually you have 2 features for each list you added. Why? Because one is for the list instance and the other is for the list template. Note that you can deactivate the feature for the list template if you don't want your users to be able to create lists from this one.


Next in the series - how to create site columns (fields) which get their data from lists.