December 19, 2008

Using SharePoint rich text editor (InputFormTextBox) in your application pages

As the SharePoint rich text editor is located in the Microsoft.SharePoint.WebControls namespace (Microsoft.SharePoint assembly), you have to add the following Register tag on your aspx page.

<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
After that, you simply have to add the InputFormTextBoxt control in your page.

<SharePoint:InputFormTextBox Rows="10" MaxLength="1000" id="txtMyRichTextBox" runat="server" RichText="true" RichTextMode="FullHtml" TextMode="MultiLine"  Height="400px" Width="250px"></SharePoint:InputFormTextBox>
The result is the following:



MSDN link: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.inputformtextbox.aspx

December 16, 2008

Issue: SPQuery doesn't return items from sub-folders

In using SPQuery object to get specific items from a list, you will see that it returns only the items from the root folder. To get also items from sub-folders, you have to set ViewAttributes with "Scope='RecursiveAll'" like in the following piece of code.

using (SPSite mySiteCollection = new SPSite("http://myserver/myspsite"))
{
    using (SPWeb mySite = mySiteCollection.OpenWeb(mySiteCollection.RootWeb.ID))
    {
        SPList studentsList = mySite.Lists["Students"];
        SPQuery query = new SPQuery();
        query.ViewAttributes = "Scope='RecursiveAll'";
        SPListItemCollection items = studentsList.GetItems(query);
    }
}

December 13, 2008

SharePoint Used Space Information

SharePoint Used Space Information is a console application which allows to retrieve information about space used (bytes) by all sites and sub-sites for a specific site collection into .csv files.

This tool uses the StorageManagementInformation method of the SPSite class to retrieve the usage information.

You can find the solution on CodePlex: http://www.codeplex.com/SPUsedSpaceInfo

December 12, 2008

How to set custom forms (new, edit and display) for a specific content type by code

Let's imagine a content type e.g. Student and you want to set custom forms for it (new, edit and display) as in the previous example. The custom forms have to be set using the NewFormUrl, EditFormUrl and DisplayFormUrl properties of the SPContentType class.

using (SPSite mySiteCollection = new SPSite("http://myserver/myspsite"))
{
    using (SPWeb mySite = mySiteCollection.OpenWeb(mySiteCollection.RootWeb.ID))
    {
        SPList studentsList = mySite.Lists["Students"];
        SPContentType studentContentType = studentsList.ContentTypes["Student"];
        string newurl = "_layouts/STUDENT/APPLICATIONPAGES/NewStudent.aspx";
        string editurl = "_layouts/STUDENT/APPLICATIONPAGES/EditStudent.aspx";
        string displayurl = "_layouts/STUDENT/APPLICATIONPAGES/DisplayStudent.aspx";
        studentContentType.EditFormUrl = editurl;
        studentContentType.NewFormUrl = newurl;
        studentContentType.DisplayFormUrl = displayurl;
        studentContentType.XmlDocuments.Delete("http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url");
        studentContentType.Update();
        studentsList.Update();
    }
}

December 08, 2008

How to set custom forms (new, edit and display) for a specific content type by CAML definition

Let's imagine a content type e.g. Student and you want to set custom forms for it (new, edit and display). The custom forms have to be declared under the XmlDocuments node of the content type CAML definition.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType
        ID="0x01004037ADCF3A5C4b648FFC4DA96C965CDE"
        Name="Student"
        Description="Create a new student"
        Version="0"
        Group="Custom Content Types" >
    <FieldRefs>
      <!-- add in and rename built-in WSS Title column-->
      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" DisplayName="Name" Sealed="TRUE"  />
      <!-- custom fields-->
      <FieldRef ID="{756D3B72-AC72-4e0a-8B6D-1E2573251816}" Name="CardNumber" DisplayName="Card Number" />
      <FieldRef ID="{0D6C76FD-A9B6-4613-9429-06385411E9D7}" Name="StudyYear" DisplayName="Study Year" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
        <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
          <New>_layouts/STUDENT/APPLICATIONPAGES/NewStudent.aspx</New>
          <Edit>_layouts/STUDENT/APPLICATIONPAGES/EditStudent.aspx</Edit>
          <Display>_layouts/STUDENT/APPLICATIONPAGES/DisplayStudent.aspx</Display>
        </FormUrls>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

November 21, 2008

A new version of SharePoint List Access Layer Generator is available

This second version of the project is always a beta, so be careful when using it.

You can find the solution on CodePlex: http://www.codeplex.com/SPLALGenerator

November 18, 2008

SharePoint 2007: Creating SharePoint Applications with Visual Studio 2008 (webcast from PDC 2008)

Here is an interesting webcast about how to build a SharePoint application using the Visual Studio 2008 extensions for SharePoint: http://channel9.msdn.com/pdc2008/BB13/

Do Less. Get More. Develop on SharePoint

A colleague sent me an interesting Microsoft link for SharePoint developers. It provides all you need to know to build powerful SharePoint solutions.

Here is the link:
http://www.microsoft.com/click/SharePointDeveloper/

November 17, 2008

CAML query on lookup columns

Let's imagine two SharePoint lists:

- Products
- Categories

In this scenario, the Products list contains a lookup column called Category pointing on the Categories list.

Now, I want to write a CAML query to get all the products list items related to the Hardware category.

The first thing coming into my mind is the following piece of code:

private SPListItemCollection GetProductsByCategory(SPFieldLookupValue Category)
{
    SPList listProducts = this._web.Lists["Products"];
    SPQuery camlQuery = new SPQuery();
    camlQuery.Query = string.Format("<Where><Eq><FieldRef Name=\"Category\" /><Value Type=\"Lookup\">{0}</Value></Eq></Where>", Category.LookupValue);
    return listProducts.GetItems(camlQuery);
}

The problem with this query appears if some categories have the same name (Hardware). It's due to the fact that the query doesn't use the ID of the category but the Name. So, you will get all the products related to all the categories having Hardware as name.

To solve that and get only the products related to the wanted category, you have to rewrite the query in setting the LookupId property of the FieldRef node to true and in using the LookupId property as value and not the LookupValue property:

private SPListItemCollection GetProductsByCategory(SPFieldLookupValue Category)
{
    SPList listProducts = this._web.Lists["Products"];
    SPQuery camlQuery = new SPQuery();
    camlQuery.Query = string.Format("<Where><Eq><FieldRef Name=\"Category\" LookupId=\"TRUE\" /><Value Type=\"Lookup\">{0}</Value></Eq></Where>", Category.LookupId);
    return listProducts.GetItems(camlQuery);
}

November 14, 2008

MSDN Event: Extending Microsoft Office and SharePoint to build Business Applications - 19/11/2008

Abstract

If your users like the comfort of using the Office suite and you would like to offer them new tools in a familiar environment: Office Business Applications (OBA) is the solution. During this session you will get a good overview of the possibilities to extend Office as well as interaction between the different products of the suite. We will also focus on the integration with SharePoint. To demonstrate this we will create a security management tool for SharePoint through an Excel document. Another point that will be shown is the development of add-ins, including the different options for deploying these.

Sessions

This year again we will have an English session in the morning and a French session in the afternoon. Below you will find two registration links, one for the English session and the other for the French session.

Registration for the English Session
(http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032391536&Culture=en-us)

Audience: Developer

Level: 300 - Advanced

Language: English
Speaker: Katrien De Graeve, Developer Evangelist, Microsoft Belgium & Luxembourg
Date: November 19th
Time: 09.00 – 12.30


Registration for the French Session (http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032391538&Culture=fr-BE)

Audience: Développeur

Level: 300 - Avancés

Language: Français
Speaker: Didier Danse
Date: 19 Novembre
Time: 13.00 – 16.30

Event Address


Technoport Schlassgoart 66, rue de Luxembourg

B.P. 144 Esch-sur-Alzette
L-4002Luxembourg

SharePoint Guidance (patterns & practices) release

Summary from MSDN:

"This guidance helps architects and developers design, build, test, deploy and upgrade SharePoint intranet applications. A reference implementation that is named the Contoso Training Management application demonstrates solutions to common architectural, development, and application lifecycle management challenges.

This guidance discusses the following:
  • Architectural decisions about patterns, feature factoring, and packaging.
  • Design tradeoffs for common decisions many developers encounter, such as when to use SharePoint lists or a database to store information.
  • Implementation examples that are demonstrated in the Training Management application and in the QuickStarts.
  • How to design for testability, create unit tests, and run continuous integration.
  • How to set up different environments including the development, build, test, staging, and production environments.
  • How to manage the application life cycle through development, test, deployment, and upgrading.
  • Team-based intranet application development.

The following areas are not discussed in the current version of this guidance:

  • Content-oriented sites that use Web content management
  • Internet and enterprise-scale SharePoint applications
  • Multilingual SharePoint applications
  • Scale or security testing of SharePoint applications "
You can find the MSDN link and the download link here:
-
http://msdn.microsoft.com/en-us/library/dd203468.aspx
- http://www.microsoft.com/downloads/details.aspx?FamilyId=C3722DBA-6EE7-4E0E-82B5-FDAF3C5EC927&displaylang=en

Another project which seems to be interesting is SharePoint 2007 SoftwareFactoryLite (still in beta) on CodePlex. This is a project based on the Microsoft Guidance Automation Toolkit.
-
http://www.codeplex.com/spalm

October 07, 2008

Visual Studio 2010 & .NET Framework 4.0 Overview

Microsoft has published an overview of the next generation of Visual Studio and .NET Framework.

Here is the link:
http://msdn.microsoft.com/en-us/vstudio/products/cc948977.aspx

October 01, 2008

How to create SharePoint alerts for lists or list items programmatically

This article will explain how to create SharePoint alert like in the following SharePoint Alert Me page. The illustrated page is the page displayed for a list. In the case of a list item, it's exactly same except that there are no Change Type and Send Alerts for These Changes sections.



Let's imagine a little console application to play the trick...

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
 
namespace UsageInformation
{
    class Program
    {
        static void Main(string[] args)
        {
            using (SPSite mySiteCollection = new SPSite("http://myserver/myspsite"))
            {
                using (SPWeb mySite = mySiteCollection.OpenWeb(mySiteCollection.RootWeb.ID))
                {
                    //Code will be put here
                }
            }
        }
    }
}

The first thing to create the alert is to use the Add method of the Alerts property of the SPUser class. This method return an instance of the SPAlert class.

string myUserLogin = @"MyDomain\MyUser";
SPUser myUser = mySite.Users[myUserLogin];
SPAlert newAlert = myUser.Alerts.Add();

To set the title of the alert, you have to use the Title property of the SPAlert class.

newAlert.Title = "My Title";

The following part of the screen corresponds to the Title property.



If the alert is an alert for a list, you have to specify it in using the AlertType property (enumeration) and to set the List property which must be an instance of the SPList class.

SPList myList = mySite.Lists["My List Name"];
newAlert.AlertType = SPAlertType.List;
newAlert.List = myList;

If the alert is an a alert for a list item, you have to specify it in using the AlertType property (enumeration) and to set the Item property must be an instance of the SPListItem class.

SPListItem myListItem = mySite.Lists["My List Name"].Items.GetItemById(1);
newAlert.AlertType = SPAlertType.Item;
newAlert.Item = myListItem;

Now you have to set the AlertTemplate property. This property must be an instance of the SPAlertTemplate class. Typically, you have to set this property with the template of the list (alert for a list) or with the template of the list containing the list item (alert for a list item).

newAlert.AlertTemplate = myList.AlertTemplate;

or

newAlert.AlertTemplate = myListItem.ParentList.AlertTemplate;

The next property to set is the EventType property (enumeration). This property correspond to Change Type section.

newAlert.EventType = SPEventType.All;

or

newAlert.EventType = SPEventType.Add;

or

newAlert.EventType = SPEventType.Modify;

or

newAlert.EventType = SPEventType.Delete;

or

newAlert.EventType = SPEventType.Discussion;

The following part of the screen corresponds to the EventType property.



The next property to set is the Filter property. This property corresponds to the Send Alerts for These Changes section. In fact, this is string which must be a CAML query.

If Anything change is selected:

newAlert.Filter = string.Empty;

If Someone else changes an item is selected:

newAlert.Filter = string.Format("<Query><Neq><Value type=\"string\">{0}</Value><FieldRef Name=\"Editor/New\"/></Neq></Query>", myUser.Name.ToLower());

If Someone else changes an item created by me is selected:

newAlert.Filter = string.Format("<Query><And><Or><Eq><Value type=\"string\">{0}</Value><FieldRef Name=\"Author/New\"/></Eq><Eq><Value type=\"string\">{0}</Value><FieldRef Name=\"Author/Old\"/></Eq></Or><Neq><Value type=\"string\">{0}</Value><FieldRef Name=\"Editor/New\"/></Neq></And></Query>", myUser.Name.ToLower());

If Someone else changes an item last modified by me is selected:

newAlert.Filter = string.Format("<Query><And><Eq><Value type=\"string\">{0}</Value><FieldRef Name=\"Editor/Old\"/></Eq><Neq><Value type=\"string\">{0}</Value><FieldRef Name=\"Editor/New\"/></Neq></And></Query>", myUser.Name.ToLower());

The following part of the screen corresponds to the Filter property.



The last properties to set are the AlertFrequency and the AlertTime. Note that the AlertTime must be set only if the AlertFrequency is different than Immediate. The AlertTime property is the next time the alert will be executed and the AlertFrequency is the frequence (enumeration): Immediate, Daily or Weekly. These properties correspond to the When to Send Alerts section.

Immediate:

newAlert.AlertFrequency = SPAlertFrequency.Immediate;

Daily and the wanted hour (e.g. 10) is > hour of today:

newAlert.AlertFrequency = SPAlertFrequency.Daily;
newAlert.AlertTime = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 10, 0, 0);

Daily and the wanted hour (e.g. 10) is <= hour of today:

newAlert.AlertFrequency = SPAlertFrequency.Daily;
newAlert.AlertTime = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 10, 0, 0);
newAlert.AlertTime = newAlert.AlertTime.AddDays(1);

Weekly and the wanted day (e.g. friday) is = today and the wanted hour (e.g. 10) is > hour of today:

newAlert.AlertFrequency = SPAlertFrequency.Weekly;
newAlert.AlertTime = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 10, 0, 0);

Weekly and the wanted day (e.g. friday) is = today and the wanted hour (e.g. 10) is <= hour of today:

newAlert.AlertFrequency = SPAlertFrequency.Weekly;
newAlert.AlertTime = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 10, 0, 0);
newAlert.AlertTime = newAlert.AlertTime.AddDays(7);

Weekly and the wanted day (e.g. sunday) is > today (e.g. friday):

newAlert.AlertFrequency = SPAlertFrequency.Weekly;
newAlert.AlertTime = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 10, 0, 0);
newAlert.AlertTime = newAlert.AlertTime.AddDays(2);

Weekly and the wanted day (e.g. wednesday) is < today

newAlert.AlertFrequency = SPAlertFrequency.Weekly;
newAlert.AlertTime = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 10, 0, 0);
newAlert.AlertTime = newAlert.AlertTime.AddDays(5);

The following part of screen corresponds to these properties.



To finish, you have to call the Update method of the instance of SPAlert.

newAlert.Update(true);

September 19, 2008

How to delete a specific user from all sites collections

The following piece code is a little console application which allows to delete a specific user from all sites collections on SharePoint server.

The application requires 3 parameters passed as arguments:
1) Authentication type: "w" (Windows authentication) or "f" (Forms authentication)
2) Domain name in case of Windows authentication or MembershipProvider name in case of Forms authentication
3) User name

using System;
using System.Web.Configuration;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
 
namespace DeleteUserFromAllSiteCollections
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                if (args == null || args.Length != 3)
                {
                    throw new ArgumentException("Invalid parameters.");
                }
 
                string authenticationType = args[0];
                string domainName = args[1];
                string userName = args[2];
 
                if (authenticationType.ToLower() != "w" && authenticationType.ToLower() != "f")
                {
                    throw new ArgumentException("Invalid authentication type parameters.");
                }
 
                string longUserName = string.Empty;
                AuthenticationMode authenticationMode;
                if (authenticationType.ToLower() == "w")
                {
                    longUserName=string.Format(@"{0}\{1}",domainName.ToUpper(),userName.ToLower());
                    authenticationMode = AuthenticationMode.Windows;
                }
                else
                {
                    longUserName = string.Format(@"{0}:{1}", domainName.ToLower(), userName.ToLower());
                    authenticationMode = AuthenticationMode.Forms;
                }
 
                SPFarm farm = SPFarm.Local;
                Console.WriteLine(string.Format("Connected with farm: {0}", farm.DisplayName));
 
                SPWebService service = farm.Services.GetValue<SPWebService>("");
                Console.WriteLine("Services has been retrieved.");
 
                foreach (SPWebApplication webApp in service.WebApplications)
                {
                    Console.WriteLine(string.Format("Connected with WebApp: {0}", webApp.DisplayName));
 
                    if (!webApp.IsAdministrationWebApplication)
                    {
                        foreach (SPUrlZone zone in webApp.IisSettings.Keys)
                        {
                            SPIisSettings setting = webApp.IisSettings[zone];
                            if (setting.AuthenticationMode == authenticationMode)
                            {
                                bool ok = true;
                                if (authenticationMode == AuthenticationMode.Forms)
                                {
                                    if (setting.MembershipProvider.ToLower() != domainName.ToLower())
                                    {
                                        ok = false;
                                    }
                                    else
                                    {
                                        Console.WriteLine(string.Format("{0} installed.", domainName.ToLower()));
                                    }
                                }
                                if(ok)
                                {
                                    foreach (SPSite siteCollection in webApp.Sites)
                                    {
                                        Guid siteCollectionId = siteCollection.ID;
 
                                        SPSecurity.RunWithElevatedPrivileges(delegate
                                        {
                                            using (SPSite elevatedSiteCollection = new SPSite(siteCollectionId))
                                            {
                                                Console.WriteLine(string.Format("Connected with SiteCollection: {0}", elevatedSiteCollection.Url));
                                                Guid siteId = elevatedSiteCollection.RootWeb.ID;
 
                                                using (SPWeb elevatedSite = elevatedSiteCollection.OpenWeb(siteId))
                                                {
                                                    Console.WriteLine(string.Format("Connected with root site: {0}", elevatedSite.Url));
 
                                                    SPUser userToRemove = null;
                                                    try
                                                    {
                                                        userToRemove = elevatedSite.SiteUsers[longUserName];
                                                    }
                                                    catch { }
 
                                                    if (userToRemove != null)
                                                    {
                                                        elevatedSite.SiteUsers.RemoveByID(userToRemove.ID);
                                                        Console.WriteLine("{0} has been deleted.", longUserName);  
                                                    }
                                                    else
                                                    {
                                                        Console.WriteLine("{0} not found.", longUserName);
                                                    }
                                                }
                                            }
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("Message: {0} {1} Stack:{2}", ex.Message, System.Environment.NewLine, ex.StackTrace));
            }
        }
    }
}

September 11, 2008

How to get usage information for a specific site collection by code

To get usage information for a site collection, have a look at the Usage property of the SPSite class.

This property is a structure which contains 5 fields:
- Storage: total amount of storage (bytes) consumed
- DiscussionStorage: amount of storage (bytes) used by the web discussion data
- Hits: cumalative number of visits
- Bandwidth: cumulative bandwith used
- Visits: cumulative number of visits

Note that 2 (Storage and DiscussionStorage) are updated in real time and 3 (Bandwidth, Hits and Visits) are updated daily by the usage analysis timer job.

The following console application displays the usage information for a specific site collection:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
 
namespace UsageInformation
{
    class Program
    {
        static void Main(string[] args)
        {
            using (SPSite siteCollection = new SPSite("http://siteCollectionUrl"))
            {
                Console.WriteLine(string.Format("SiteCollection Url: {0}", siteCollection.Url));
                Console.WriteLine(string.Format("Storage: {0}", siteCollection.Usage.Storage));
                Console.WriteLine(string.Format("Discussion Storage: {0}", siteCollection.Usage.DiscussionStorage));
                Console.WriteLine(string.Format("Bandwidth: {0}", siteCollection.Usage.Bandwidth));
                Console.WriteLine(string.Format("Hits: {0}", siteCollection.Usage.Hits));
                Console.WriteLine(string.Format("Visits: {0}", siteCollection.Usage.Visits));
 
                Console.WriteLine(string.Format("Press a touch to exit..."));
                Console.ReadLine();
            }
        }
    }
}

SharePoint List Access Layer Generator

SPList Access Layer Generator is a windows application which allows developers to generate classes to access SharePoint lists like an ORM. This project has been initiated to be compliant with the Rapid Application Development methodology.

The first version of this project is always a beta, so be careful when using it.

You can find the solution on CodePlex: http://www.codeplex.com/SPLALGenerator

September 10, 2008

Automated SharePoint Site Branding on MSDN Magazine (July 2008)

Ted Patisson has written an interesting article about how to automate SharePoint site branding. It's really helpful when you have a company brandind for a SharePoint site and you want to apply automatically this branding to all sub-sites and so on.

Link to the article: http://msdn.microsoft.com/en-us/magazine/cc700347.aspx

How to display the SharePoint waiting page when doing long operations in your code

Displaying the SharePoint waiting page with the rotating gear image is easy. The Microsoft.SharePoint namespace provides the SPLongOperation class to play the trick.

As this class implements the IDisposable interface, the best is to use a using statement like in the following example:

void buttonProcess_Click(object sender, EventArgs e)
{
    using (SPLongOperation operation = new SPLongOperation(this.Page))
    {
        // Define the url to be redirected after the long operation
        string url = "http://myserver/myotherpage.aspx";
 
        operation.LeadingHTML = "Please wait...";
        operation.TrailingHTML = "Description...";
 
        operation.Begin();
        //Place here the code that takes a long time to be executed
        operation.End(url);
    }
}

MSDN link: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splongoperation.aspx

September 05, 2008

Patrick Tisseghem passed away


It's with sadness I learned this morning that Patrick Tisseghem passed away on Wednesday 3 September 2008. He was like a mentor for the all the SharePoint developers.
All my thoughts go out to his family, friends and colleagues. You will miss the SharePoint community.

August 19, 2008

SPSite Storage Information

SPSite Storage Information provides storage reports about documents, documents libraries and lists for a specific site collection in SharePoint. The reports can be exported in excel or pdf.

This tool uses the StorageManagementInformation method of the SPSite class to retrieve the storage information.

You can find the solution on CodePlex:
http://www.codeplex.com/SPSiteStorageInfo

August 14, 2008

How to display more than 50 items in SharePoint menu

As you know, the SharePoint navigation is based on the ASP.NET 2 SiteMap Provider. By default the limit is 50 items per menu.

Have a look on the SiteMap Provider part of the web.config:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration>
  ...
  <system.web>
    ...
    <siteMap defaultProvider="CurrentNavSiteMapProvider" enabled="true">
      <providers>
        <add name="SPNavigationProvider" type="Microsoft.SharePoint.Navigation.SPNavigationProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SPSiteMapProvider" type="Microsoft.SharePoint.Navigation.SPSiteMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SPContentMapProvider" type="Microsoft.SharePoint.Navigation.SPContentMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SPXmlContentMapProvider" siteMapFile="_app_bin/layouts.sitemap" type="Microsoft.SharePoint.Navigation.SPXmlContentMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="AdministrationQuickLaunchProvider" description="QuickLaunch navigation provider for the central administration site" type="Microsoft.Office.Server.Web.AdministrationQuickLaunchProvider, Microsoft.Office.Server.UI, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SharedServicesQuickLaunchProvider" description="QuickLaunch navigation provider for shared services administration sites" type="Microsoft.Office.Server.Web.SharedServicesQuickLaunchProvider, Microsoft.Office.Server.UI, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="GlobalNavSiteMapProvider" description="CMS provider for Global navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Global" EncodeOutput="true" />
        <add name="CombinedNavSiteMapProvider" description="CMS provider for Combined navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Combined" EncodeOutput="true" />
        <add name="CurrentNavSiteMapProvider" description="CMS provider for Current navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Current" EncodeOutput="true" />
        <add name="CurrentNavSiteMapProviderNoEncode" description="CMS provider for Current navigation, no encoding of output" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Current" EncodeOutput="false" />
        <add name="SiteDirectoryCategoryProvider" description="Site Directory category provider" type="Microsoft.SharePoint.Portal.WebControls.SiteDirectoryCategoryProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="MySiteMapProvider" description="MySite provider that returns areas and based on the current user context" type="Microsoft.SharePoint.Portal.MySiteMapProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="MySiteLeftNavProvider" description="MySite Left Nav provider that returns areas and based on the current user context" type="Microsoft.SharePoint.Portal.MySiteLeftNavProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="UsagePagesSiteMapProvider" description="Provider for navigation in Portal Usage pages" type="Microsoft.SharePoint.Portal.Analytics.UsagePagesSiteMapProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      </providers>
    </siteMap>
    ...
  </system.web>
  ...
</configuration>

To change the limit, simply add the DynamicChildLimit attribute to the GlobalNavSiteMapProvider, CombinedNavSiteMapProvider, CurrentNavSiteMapProvider and CurrentNavSiteMapProviderNoEncode nodes and specify the limit e.g. 100:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration>
  ...
  <system.web>
    ...
    <siteMap defaultProvider="CurrentNavSiteMapProvider" enabled="true">
      <providers>
        ...
        <add name="GlobalNavSiteMapProvider" ... DynamicChildLimit="100" />
        <add name="CombinedNavSiteMapProvider" ... DynamicChildLimit="100" />
        <add name="CurrentNavSiteMapProvider" ... DynamicChildLimit="100" />
        <add name="CurrentNavSiteMapProviderNoEncode" ... DynamicChildLimit="100" />
        ...
    </providers>
    </siteMap>
    ...
  </system.web>
  ...
</configuration>

July 23, 2008

How to display all the web applications where a custom MembershipProvider is installed

The following piece code is a little console application which displays all the web applications where a custom MembershipProvider passed as argument is installed:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;
using System.Web.Configuration;
 
namespace DisplayWebAppsUsingACustomProvider
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                if (args == null  args.Length != 1)
                {
                    throw new ArgumentException("Invalid argument.");
                }
 
                string myMembershipProvider = args[0];
 
                SPFarm farm = SPFarm.Local;
                Console.WriteLine(string.Format("Connected to farm: {0}.", farm.DisplayName));
 
                SPWebService service = farm.Services.GetValue<SPWebService>("");
                Console.WriteLine("Services has been retrieved.");
 
                foreach (SPWebApplication webApp in service.WebApplications)
                {
                    Console.WriteLine(string.Format("Connected to Web Application: {0}.", webApp.DisplayName));
 
                    if (!webApp.IsAdministrationWebApplication)
                    {
                        foreach (SPUrlZone zone in webApp.IisSettings.Keys)
                        {
                            SPIisSettings setting = webApp.IisSettings[zone];
                            if (setting.AuthenticationMode == AuthenticationMode.Forms)
                            {
                                if (setting.MembershipProvider.ToLower() == myMembershipProvider.ToLower())
                                {
                                    Console.WriteLine(string.Format("MembershipProvider \"{0}\" found.", myMembershipProvider));
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("Message: {0} {1} Stack:{2}.", ex.Message, System.Environment.NewLine, ex.StackTrace));
            }
            Console.WriteLine("Press a touch to exit.");
            Console.ReadLine();
        }
    }
}