Sep 23, 2007

Create and deploy a Sharepoint Feature

Suppose you need to replace the SmallSearchInputBox on the sharepoint site with a new feature. Follow these steps:

step1 : create a copy of existing feature e.g. controlLightUp
Thus copy this folder from 12\Template\Features\CustomLightUp to 12\Template\Features\NewSearchArea

Step2: modify feature.xml to contain the new GUID and add a reference to the element.xml (within a subdirectory or the same directory as feature.xml, whichever you prefer) which describes the feature.
Specify if the feature should be HIDDEN or displayed in the Sharepoint site settings
Specify Title and Description if this feature is NOT Hidden

Step 3: then modify the elements.xml file in controls folder to have the correct settings. Scope can take one of the following values: FARM, Webapplication, Web and Site
Site is SiteCollection
Web is Site
Web Application is parent of Sitecollection
FARM is server wide enabling of the feature

Step4: suppose CustomLightUp feature is installed at FARM level snd it is referenced through a delagate control in the master page and its control id "SmallSearchInputBox", and you want to create a new feature at the Site scope and for the same delegate control
Then there are 2 ways to achioeve this

1: rename the Delegate control id from "SmallSearchInput" to "newSearch" then then make the modification in elements.xml to contain this new control id. then install the feature at Site level using stsadm utility

2. you can keep the control id the same i.e. "SmallSearchInput" but then modify the Sequence value in elements.xml to have a value less than 100.
(for more on this refer to my previous blog on delegate control) Then install the feature at the site level using stsadm
command is stsadm -o installfeature -filename NewSearchArea\feature.xml
stsadm -o activatefeature -filename NewSearch\feature.xml -url http://w.c.com

For automatic deployment of the feature read this:
http://www.codeplex.com/wspbuilder
Or
http://msdn.microsoft.com/msdnmag/issues/07/05/OfficeSpace/
and
http://msdn.microsoft.com/msdnmag/issues/07/08/OfficeSpace/

if you want to list all existing features then you need to extend the stsadm utility:
http://sharepointsolutions.blogspot.com/2006/09/extending-stsadmexe-with-custom.html
and
http://msdn2.microsoft.com/en-us/library/bb417382.aspx
and
http://www.andrewconnell.com/blog/articles/MossStsadmWcmCommands.aspx
and
http://stsadm.blogspot.com/2007/08/enumerate-features.html

Sep 21, 2007

Delegate Control in Sharepoint

Essentially the Delegate Control provides an alternative to adding user controls and server controls to a .aspx page in the normal way. By this, I mean adding the control to the page by dragging from the toolbox in the development environment or by adding the appropriate markup manually. Instead, with a Delegate Control all we do is add the markup to instantiate a Delegate Control instance, and use a Feature to specify separately which control should actually be loaded. What this effectively gives us is the ability to control what controls are used on a page without having to directly modify and redeploy master pages/page layouts. This extra level of abstraction can be quite powerful, since any feature scope can be used with the Delegate Control. I'll come back to this, but enough theory for now. Here's how it's used:

First off, we need a Delegate Control declaration on our page. This will look something like:

<SharePoint:DelegateControl runat="server" ControlId="PageHeader">

</SharePoint:DelegateControl>


Only thing to note here at this stage is the ControlId attribute - the Feature we create will use this to substitute the real user/server control.

Then we have the feature.xml file, where we specify the feature details (including scope):

<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Id="373042ED-718D-46e2-9596-50379DA4D522"

Title="COB.Demos.DelegateControls"

Description="Specifies which user control should be used for the 'PageHeader' DelegateControl used on the site master page. The replacement user control is stored in the CONTROLTEMPLATES directory." Scope="Farm"

Hidden="FALSE"

Version="1.0.0.0">

<ElementManifests>

<ElementManifest Location="elements.xml"/>

</ElementManifests>

</Feature>


As always, the 'instructions' for the feature are in the element manifest:

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

<!-- using a sequence number LOWER than default of 100 so our custom control gets loaded -->

<Control Id="PageHeader" Sequence="90" ControlSrc="~/_ControlTemplates/COBPageHeader.ascx" />

</Elements>

This is where we specify which control should actually be used. In addition to specifying the path, the key thing is that the 'Sequence' attribute contains a value lower than any other <Control> instructions for this control (i.e. ID of 'PageHeader'). This is especially important when we are overriding an existing Delegate Control created by Microsoft - here the default value is 100 so your sequence must be lower than this for your control to be loaded instead.

In addition to creating and activating this feature, the actual .ascx file must exist in the location specified. It can be copied to the CONTROLTEMPLATES directory manually, but a better idea is to wrap the feature up as a solution, since solution packages can also deploy files. To deploy the .ascx file along with the solution, your solution manifest file should look something like:

<Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="E8694626-60F8-4d07-9140-8F9F634020DE">

<FeatureManifests>

<!-- note this is the location in the cab file! -->

<FeatureManifest Location="COB.Demos.DelegateControls\feature.xml" />

</FeatureManifests>

<TemplateFiles>

<TemplateFile Location="CONTROLTEMPLATES\COBPageHeader.ascx" />

</TemplateFiles>

</Solution>

These files would now all be packaged as a solution (.wsp) in the usual way with makecab.exe. When the solution is deployed, the file will be copied to the right place on all the web front-ends in your farm, and when the feature is activated SharePoint will know that it should henceforth load 'COBPageHeader.ascx' for any Delegate Control with an ID of 'PageHeader'.

So what's so great about that?

Well, a couple of things:-

  • I can now override which control a page should load without having to go back, edit the template and redeploy
  • By using a feature scoped at 'Web', I can effectively use a different page header for different areas of my site without requiring different templates or code. (Note I've not tested this extensively, but since the <Control> element can be used at scope Web, Site, WebApplication or Farm, this should be perfectly feasible.)
  • I can use any standard .Net user control or server control, so for anybody familiar with Jan Tielen's SmartPart, this provides similar capability.

In terms of functionality, there's a couple of other things I want to highlight:

  • Parameters can be passed to the control via the declaration on the page. To read these, the control's implementation should walk up the control tree to get the values. An example would be:

<SharePoint:DelegateControl runat="server"

ControlId="PageHeader" MyParam="MyValue">

</SharePoint:DelegateControl>

  • By adding AllowMutiple="true" to the declaration, you can make the Delegate Control load more than one user/server control.
  • As mentioned earlier, many of the controls used on default.master are loaded using the Delegate Control. These include global links such as My Site/My Links and the publishing console. So using this approach, customizing the publishing console is a simple matter of providing a replacement .ascx and creating a feature as described here!

Automating Dev, QA, Staging, and Production Web.Config Settings with VS 2005

One of the questions I get asked fairly regularly is: "how can I can easily change different configuration settings in my web.config file based on whether my application is in a dev, qa, staging or production mode?" The most common scenario for this is one where an application uses different database connection-strings for testing and production purposes.

It turns out you can easily automate this configuration process within the Visual Studio build environment (and do so in a way that works both within the IDE, as well as with command-line/automated builds). Below are the high-level steps you take to do this. They work with both VS 2005 and VS 2008.

  1. Use ASP.NET Web Application Projects (which have MSBuild based project files)
  2. Open the VS Configuration Manager and create new "Dev", "QA", "Staging" build configurations for your project and solution
  3. Add new "web.config.dev", "web.config.qa", and "web.config.staging" files in your project and customize them to contain the app's mode specific configuration settings
  4. Add a new "pre-build event" command to your project file that can automatically copy over the web.config file in your project with the appropriate mode specific version each time you build the project (for example: if your solution was in the "Dev" configuration, it would copy the web.config.dev settings to the main web.config file).

Once you follow these steps, you can then just pick the mode your solution is in using the configuration drop-down in the VS standard toolbar:

The next time you build/run after changing the configuration mode, VS will automatically modify your application's web.config file to pick up and use the web.config settings specific to that build configuration (so if you select QA it will use the QA settings, if you select Deploy it will use the Deploy settings).

The benefit with this approach is that it works well in a source control environment (everyone can sync and build locally without having to make any manual changes on their local machines). It also works on a build server - including with scenarios where you are doing automated command-line solution builds.

To learn more about the exact steps to set this up, please read the Managing Multiple Configuration File Environments with Pre-Build Events post that Scott Hanselman published earlier tonight. Also check out ScottGu's ASP.NET Tips, Tricks, and Gotchas page for other ASP.NET Tips/Tricks recommendations.

Sep 18, 2007

multi column sorting of a typed collection

Use the following One line code for multi-column or single column sorting of a typed collection:

List<Liability> liabList = new List<Liability>();

liabList.Sort(delegate(Liability l1, Liability l2)
{ int r = l1.Type.CompareTo(l2.Type);
if (r == 0 && l1.HolderName != null)
r = l1.HolderName.CompareTo(l2.HolderName);
if (r == 0)
r = l1.Amount.CompareTo(l2.Amount);
return r;
} );