SharePoint - Register an assembly as a safe control in the Web.config file

on Friday, February 19, 2010

In order for you to use your own custom assembly with your web parts and other little bits, you will need to add your safe control to the web.config file.  However, you need to think "WEB FARM" with many servers hosting the web application so I will show you a couple ways to do this.

The entry in the web.config

You need to place a SaveControl element entry into the web.config file of the web application.  The entry looks like the following:

   1: <configuration>

   2:   <SharePoint>

   3:     <SafeControls>

   4:       <SafeControl Assembly="[Assembly Name]" Namespace="[Namespace]" TypeName="*" Safe="True" />

   5:     </SafeControls>

   6:   </SharePoint>

   7: </configuration>
Assembly The name of your assembly needs to added to this section. Although you can simply type the name of the DLL hosting the control into the Assembly element, it is important to not that this is not the recommended practice.  Rather, use a full four part name; i.e. [assembly], version=[version], culture=[culture], publickeytoken=[publickeytoken]Namespace The namespace that your web controls are in.  If you have your controls in multiple namespaces, you will need to add one <SafeContol ...> element for each control.TypeName The name of the web control which is allowed to be executed with the SharePoint web application.  Should your namespace have multiple web controls, you do not need to register each control.  You can simply use * (asterisk) to indicate the dll.Safe A boolean flag, indicating whether the control is treated as safe (true) or unsafe (false). AllowRemoteDesignerA boolean flag, indicating whether the control can be loaded by a remote designer, such as SharePoint Designer.


Sample


   1: <SafeControl Assembly="Brett.DemoParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f03e5f7a44d50a3a" 

   2:              Namespace="Brett.SharePoint.WebParts" 

   3:              TypeName="*" 

   4:              Safe="True" 

   5:              AllowRemoteDesigner="True" />


Methods of updating the web.config file


There are three ways you can update the web.config file,


  • Manually adding the SafeControl to the web.config
  • Adding the SafeControl to the web.config with code
  • Deploy the assembly using a solution package

Manually editing the web.config (bad)


This approach may sound the easiest and quickest way as you simply open up your favourite xml editor, find the <SafeControls> element and add your own control into it.


WARNING!

If you do it this way, you are looking for trouble in a farm as you will need to remember to change the web.config modification for all your servers in the farm as well as all the web applications on the farm that use the custom control.  So should you have a really awsome web part that is used within 5 web applications hosted on your farm of 3 servers, you will need to make the modification to 15 web.config's .. have fun.


Also should you add a new server to your farm, please remember to add the entry the web.config.


Bottom line, this is the worst possible way you can do it  and stay away from doing it this way


Adding the SafeControl to the web.config with code (good)


SharePoint provides a class called SPWebConfigModification which has a set of modification commands in a collection.  These modification commands are applied to the default web.config of the Web Application.  These configuration modification commands will also be added and applied to all servers in a farm.   Finally, should a new server be added to the farm, these modifications will also be applied.


The following code could be added to the FeatureActivated override method in your feature that deploys the web part.


   1: public override void FeatureActivated(SPFeatureReceiverProperties properties) 

   2: {

   3:     // A reference to the features Site Collection

   4:     SPSite site = null;

   5:  

   6:     // Get a reference to the Site Collection of the feature

   7:     if (properties.Feature is SPWeb)

   8:     { site = ((SPWeb)properties.Feature.Parent).Site; }

   9:     else if (properties.Feature.Parent is SPSite)

  10:     { site = properties.Feature.Parent as SPSite; }

  11:  

  12:     if (site != null)

  13:     {

  14:         SPWebApplication webApp = site.WebApplication;

  15:  

  16:         // Create a modification

  17:         SPWebConfigModification mod = new SPWebConfigModification(

  18:             "SafeControl[@Assembly=\"MyAssembly\"][@Namespace=\"My.Namespace\"]"

  19:                 + "[@TypeName=\"*\"][@Safe=\"True\"][@AllowRemoteDesigner=\"True\"]"

  20:             , "/configuration/SharePoint/SafeControls"

  21:             );

  22:  

  23:         // Add the modification to the collection of modifications

  24:         webApp.WebConfigModifications.Add(mod);

  25:  

  26:         // Apply the modification

  27:         webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

  28:     }

  29: }

Deploy the assembly using a solution package (best)


The preferred way to provision your features, web parts and assemblies is by creating a Solution Package (.wsp file).  You will add add your assembly, the manifest.xml file and all your other components and resources into the cabinet.


You will need to add the following entry into the manifest.xml


   1: <Solution SolutionId="{1E0FDA58-6611-423a-92EC-8E7355810CEE}"

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

   3:   <FeatureManifests  />

   4:   <ApplicationResourceFiles />

   5:   <CodeAccessSecurity />

   6:   <DwpFiles />

   7:   <Resources />

   8:   <RootFiles />

   9:   <SiteDefinitionManifests />

  10:   <TemplateFiles />

  11:   

  12:    <Assemblies>

  13:       <Assembly DeploymentTarget="WebApplication" Location="Brett.DemoParts.dll">

  14:          <SafeControls>

  15:             <SafeControl Assembly="Brett.DemoParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f03e5f7a44d50a3a"

  16:                          Namespace="LitwareWebParts" 

  17:                          TypeName="*" 

  18:                          Safe="True"                         

  19:                          />

  20:          </SafeControls>

  21:       </Assembly>

  22:    </Assemblies>

  23: </Solution>

  24:  

Key highlights

DeploymentTarget The depoloyment target is location where the assembly will be copied to and can ether be the bin folder of the WebApplication or it could be the GlobalAssemblyCache (GAC)Location The location of the assembly within the cabinet file. SafeControl A SafeControl element entry as described at the beginning of the post.   


Using this method, your assembly will be correctly deployed the servers in the farm as well as added to the safe controls of the web application.  Again any new server added to the farm will automatically get all the solution packages deployed.


Site Pages & PageParserPath

on Thursday, February 18, 2010

Hi,

You can have two kind of Site Pages.
1. Uncustomized(Ghosted) which resides in the file system.
2. Customized which are stored in the Content Database.

UnCustomized Pages can be created using visual studio and can be deployed using features.

Sample ASPX Page

<%@ Page Language="C#" MasterPageFile="~masterurl/default.master" meta:progid="SharePoint.WebPartPage.Document" Inherits="CustomizedPageLibrary.PageTemplate,CustomizedPageLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fa90fd1d7c28abf3" %>

<asp:Content ID="Content2" runat="server" ContentPlaceHolderID="PlaceHolderMain">
<asp:Label ID="lblHello" runat="server" BackColor=Red></asp:Label>
<asp:Button ID="btnHello" runat="server" OnClick="btnHello_Click"/>
</asp:Content>
 
 Code Behind

Create a class library project and add System.Web and Microsoft.SharePoint.Publishing dll references.
Then add following class and strong name the dll.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Publishing;
using System.Web.UI.WebControls;

namespace CustomizedPageLibrary
{
    public class PageTemplate : PublishingLayoutPage
    {
        protected System.Web.UI.WebControls.Label lblHello;
        protected Button btnHello;
        void Page_Load(object sender, EventArgs e)
        {
            lblHello.Text = "Hello1";
        }
        protected void btnHello_Click(object sender, EventArgs e)
        {
            lblHello.Text = "Hello" + DateTime.Now.ToString();
        }
    }

}


Install the assembly in the GAC


To deploy the site page into the site's Shared Documents library
feature.xml

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="597D8309-C964-48ef-8D24-D5C60C94A832"
         Title="MSDN Uncustomized Page Feature"
         Scope="Web">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>
    <ElementFile Location="PageTemplate.aspx" />
  </ElementManifests>
</Feature>



elements.xml
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Url="Shared Documents">
    <File Url="PageTemplate.aspx" Name="SamplePage.aspx" Type="GhostableInLibrary" />
  </Module>
</Elements>


Note: If you don't want to deploy it to Some doclib then you can use Type="Ghostable" as well.


Customized Pages


The aspx file above can be uploaded into some document library and the page is ready to be used if you don't have any inline code or any server side code to execute. If you want to execute some serverside code then you need to add following entry in the web.config in <PageParserPaths> element. Any page in the content database that needs to execute server side code needs to have the PareParserPath entry in web.config file.

<PageParserPaths>
        <PageParserPath VirtualPath="/Shared Documents/*" CompilationMode="Always"
AllowServerSideScript="true" IncludeSubFolders="true"/>
</PageParserPaths>

Move SiteCollections between WebApplications

on Tuesday, January 26, 2010

edit: Please read this blog post before using 'mergecontentdb' data corruption may occur

On multiple occasions as a SharePoint administrator I have needed to move a Site Collection from one Content Database to another one. In the past this process was very painful and very manual. In this blog post I will show you how to move Site Collections between Content Databases with a single STSADM command using the "mergedbs" operation that was introduced in KB934525.

Why would I need to move a Site Collection to a different Content DB? This comes up for a variety of reasons. For instance, because of restore times, I like to keep my databases under a certain size. While I try to work with my Site Collections owners to plan accordingly sometimes they grow larger than we had imagined. When this happens I need to shuffle Site Collections around to keep my databases in harmony. There are other times when I would do it if it were more convenient. If Site Collections are not growing as expected, I may want to consolidate several into a smaller Content DB. I may also want to move less active Site Collections to Content DBs on slower discs, or move Site Collections to Content DBs that reflect geographic regions. Whatever the reason, in the past to move a Site Collection you had to go through the following steps manually;

  1. Lock the Site Collection
  2. Back the Site Collection up
  3. Delete the Site Collection
  4. Set all your Content Databases' maximum allowed sites to the number of current sites.
  5. Set the Content Database you want the Site Collection to go into to allow one more Site Collection.
  6. Restore the Site Collection
  7. Unlock the Site Collection
  8. Adjust your Content Database maximums to allow new sites to be created.

All of these steps could be done with STSADM so you could build scripts and move through the process quickly. In one of the recent security patches (KB934525) for WSS and MOSS Microsoft slipped in a new STSADM operation, mergecontentdbs. I assume this operation was added with the intention of merging Content DBs, but it can also be used to split them. This blog post will walk you through both uses. Let's start with the configuration below:

You can see in this screenshot that I have three Site Collections in two Content DBs; WSSContent and WSSContent2. Let's move http://barcelona/sites/stsadm from WSS_Content to WSS_Content2. If you get the help for the mergecontentdbs operation it looks like this:

We want to use operation 3, Read from file. STSADM has given us a clue about the file needed, it is generated from stsadm –o enumsites. I'll go ahead and run that and pipe it to a file like this:

This will produce a file, mysites.xml, that contains my site collections. To move http://barcelona/sites/stsadm we'll remove all of the other Site Collections except for that one from mysites.xml and save it. You don't need to worry about changing the Site Count at the top, or any of the other Site Collection information in the file, STSADM only grabs the URLs out. I only have two Content Databases so the decision of which database to move the Site Collection to is easy. What if I had many Content Databases? You can use the first operation, Analyze, to get an idea of how your Content Databases are laid out. Let's see how that looks:

You can see here where I got the idea to use the filename mysites.xml. The thing I love best about this screen is that you can just cut and paste the final command into your Command Prompt if you'd like. I think Microsoft did a great job with the usage on this command. One thing to note is that the –url parameter is NOT the URL of the Site Collection you want to move, it's the URL of the Web Application that the Site Collection is in. Since we've already created our file and edited it, let's go ahead and run the command.

That's all there is to it. After an iisreset we see that the Site Collection http://barcelona/sites/stsadm is now in WSS_Content2. You can confirm it by looking in Central Administration > Applications > Content Databases before and after you run the command.

I have one final thing to show you, what I imagine is the intended usage of mergecontentdbs, merging two Content Databases. If we use the second operation STSADM will simply move all the Site Collections from the Source database to the Destination database. Let's move all of the sites in WSS_Content2 back into WSS_Content.

I think that picture pretty well sums it all up. Now all the Site Collections in the http://barcelona Web Application are in WSS_Content, right where we want them. I think Microsoft did a pretty good job with this addition to STSADM. Enjoy it.

I'd like to give a special shout out to Joel Oleson for telling me to look for this little gem.

tk

Move Site between site collections

How To: Move a single Site between Site Collections

Hey,

I'm hearing a lot of this question in many variations and I figured it's time to solve it once and for all. The problem is well known: trying to move a WSS Site between 2 different places (such as Site Collections) is still not something we're doing with a click of a button. There is no real and easy of doing so and I've heard about many "nasty" solutions (such as Backup/Restore for entire Site Collection, Copy-Pasting everything with the Explorer View and many other messy evils).

It looks like multiple teams in Microsoft have been tasked with this issue since we actually got 3 different ways to solve it:

  • SharePoint Designer Backup/Restore - Definitely the easiest way to move sites around but only WHEN IT WORKS (since that's not a very consistent feature in SPD). To use this method, simply go to Menu --> Site --> Administration --> Backup Web Site and enter the URL of the WSS site you want to move. You can also include/exclude other subsites in the archive you're creating. Restoring it to the new Site Collection is done with the Restore Web Site feature in SPD. Again, remember this is not too consistent so always try to restore before deleting an original site (Even when you get the "Backup Operation was completed successfully" message!). 
  • Stsadm.exe export/import - The stsadm.exe admin utility is not a new tool but in the 2007 it has many improvements. Now, we can use stsadm as a way to import and export single sites. By the way, this is actually how Share Point Designer creates the archive in the mentioned SPD method. Don't get confused with the backup/restore operations in stsadm.exe - those operations were already available in 2003 but they are used for entire Site Collections rather than a single site (and in our case it's a major overkill). Sounds great huh? Well, just like the SharePoint Designer way, it could easily become a MAJOR NIGHTMARE when it's not working so let me give you some tips. I hope this will reduce the amount of time spent CURSING THE HELL of our beloved stsadm's command line window and the its log file.
  1. The default cabsize value is 25 Mb which is VERY lame for big sites! Always define ur own cabsize (up to 1 GB...)
  2. It is highly recommended to add the “-haltonwarning” or “-haltonfatalerror” parameters. You'll be able to see a list of possible problems before proceeding with the creating on the archive.
  3. If still encounter failures and you don't understand WTF that could be, You might want to try the –nofilecompression switch. Somehow, exports tend to fail in much bigger numbers when you try to compress them.

And to sum it all up, here's the complete command with all of the available switches for exporting/importing with stsadm.exe:

stsadm -o export -url <URL to be exported> -filename <export file name> [-overwrite] [-includeusersecurity] [-haltonwarning] [-haltonfatalerror] [-nologfile] [-versions <1-4> 1= Last major version for files and list items (default), 2= The current version, either the last major or the last minor, 3= Last major and last minor version for files and list items, 4= All versions for files and list items] [-cabsize <integer from 1-1024 megabytes> (default: 25)] [-nofilecompression] [-quiet]

stsadm -o import -url <URL to import to> -filename <import file name> [-includeusersecurity] [-haltonwarning] [-haltonfatalerror] [-nologfile] [-updateversions <1-3> 1= Add new versions to the current file (default), 2= Overwrite the file and all its versions (delete then insert),3= Ignore the file if it exists on the destination] [-nofilecompression] [-quiet]

  • Content Deplyoment - Ok, now we're really talking! Let the real fun begin! This is probably the coolest and by far the most elegant way for synchronizing content between Site Collections. Although this is for a Site Collection level - it's a great way to make a lasting connection and keep moving new content between environments. Before using this method, you need to be familiar with two core conceptual objects: Paths and Jobs. A Path is set of definitions that represents a connection between the source environment and the destination environment. The path contains information about which source web application and site collection you are deploying, authentication information for the destination environment, and the web application and site collection on the destination MOSS. However, a path by itself doesn’t actually deploy any content - it's only a set of definitions. In order to sync the environment, you must create a Job. Each job is associated with a path, and determines exactly which sites in the source site collection will be deployed and on what schedule.

Now the really cool thing about this method: It uses the same logic and internal audit/log files as the Index jobs. That means that you can define a job that only deploys the changes since the last successful deployment and this could for a single item/document level. Great for saving bandwidth and time. Furthermore, if there are no changes since the previous job, the deployment will complete without redoing any unnecessary work. Of course, full deployments every time can be configured if that’s what you really want but this is not necessary in most cases.

    Awesome hug? Although this is for Site Collection level, I think it addresses the main scenario that is main reason for wanting to move a list or a whole site between places: Replication between the Testing environment to the real Production environment. Using this method, you can define it once and deploy testing versions whenever you think you're done playing and it's time to publish your changes. You can find the Content Deployment management interface under the SharePoint Central Administration site. One aspect of content deployment that you should be aware of is that it will only deploy content, not any dependent assemblies/controls/webparts, etc.  Administrator is responsible for moving the assemblies for controls and webparts to the destination farm.

In conclusion - We're dealing here with 2 types of scenarios: If we're talking about moving an entire site ONCE between Site Collections - the SPD and stsadm.exe ways are preferred and you should just use them. If you're talking about synchronization between two environments and it's something that should happen every once in a while - we'll need that lasting connection that is provided through Content Deplyoment.

Impersonate another user c#

on Friday, December 4, 2009

public class Impersonator
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;

WindowsImpersonationContext impersonationContext;

[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);



public bool impersonate(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;

if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}

public void undoImpersonation()
{
impersonationContext.Undo();
}
}

//Sample Code

Impersonator imp = new Impersonator();
bool isTrue=imp.impersonate("testuser1", "buildmachine", "password");
if (isTrue)
{
items = testDocLib.GetItems(query);

Console.WriteLine(items.Count);
imp.undoImpersonation();
}

SharePoint Hard Limits and Recommendation

on Thursday, December 3, 2009

Entity Max Permissible Size
Site Name 128 characters
Site URL 255 characters
Display name 128 characters
Connection string 384 characters
Email address 128 characters
Version numbers 064 characters
Virtual Server Friendly Name 064 characters
SQL Database Name 123 characters
SQL Database Column 128 characters
SQL Database Table Name 128 characters
SQL Role Name 128 characters
Server Name 128 characters
Windows User Name 300 characters
Windows Password 300 characters
Dependencies per object 032 objects
Zone enumeration value 004 zones
Default SQL command timeout 300 seconds
Number of simultaneous workflows that can be run 015


Site object

Guidelines for acceptable performance Notes Scope of impact when performance degrades
Site collection 50,000 per Web application Total farm throughput degrades as the number of site collections increases. Farm
Web site 250,000 per site collection You can create a very large total number of Web sites by nesting the subsites. For example, 100 sites, each with 1000 subsites, is 100,000 Web sites. The maximum recommended number of sites and subsites is 125 sites with 2,000 subsites each, for a total of 250,000 sites. Site collection
Subsite 2,000 per Web site The interface for enumerating subsites of a given Web site does not perform well as the number of subsites surpasses 2,000. Site view
Document 5 million per library You can create very large document libraries by nesting folders, using standard views and site hierarchy. This value may vary depending on how documents and folders are organized, and by the type and size of documents stored. Library
Item 2,000 per view Testing indicates a reduction in performance beyond two thousand items. Using indexing on a flat folder view can improve performance. List view
Document file size 50MB (2GB max*) File save performance is proportional to the size of the file. The default maximum is 50 MB. This maximum is enforced by the system, but you can change it to any value up to 2 GB. Library, file save performance
List 2,000 per Web site Testing indicates a reduction in list view performance beyond two thousand entries. List view
Field type 256 per list This is not a hard limit, but you might experience list view performance degradation as the number of field types in a list increases. List view
Column 2,000 per document library4,096 per list This is not a hard limit, but you might experience library and list view performance degradation as the number of columns in a document library or list increases. Library and list view
Web Part 50 per page This figure is an estimate based on simple Web Parts. The complexity of the Web Parts dictates how many Web Parts can be used on a page before performance is affected. Page

The following table lists the recommended guidelines for people objects.


People object

Guidelines for acceptable performance Notes
Users in groups 2 million per Web site You can add millions of people to your Web site by using Microsoft Windows security groups to manage security instead of using individual users.
User profile 5 million per farm This number represents the number of profiles which can be imported from a directory service, such as Active Directory, into the people profile store.
Security principal 2,000 per Web site The size of the access control list is limited to a few thousand security principals (users and groups in the Web site).

The following table lists the recommended guidelines for search objects.


Search object

Guidelines for acceptable performance Notes
Search indexes One per SSPMaximum of 20 per farm Office SharePoint Server 2007 supports one content index per SSP. Given that we recommend a maximum of 20 SSPs per farm, a maximum of 20 content indexes is supported. Note that an SSP can be associated with only one index server and one content index. However, an index server can be associated with multiple SSPs and have a content index for each SSP.
Indexed documents 50,000,000 per content index Office SharePoint Server 2007 supports 50 million documents per index server. This could be divided up into multiple content indexes based on the number of SSPs associated with an index server.
Content sources 500 per SSP* This is a hard limit enforced by the system.
Start Addresses 500 per content source* This is a hard limit enforced by the system.
Alerts 1,000,000 per SSP This is the tested limit.
Scopes 200 per site This is a recommended limit per site. We recommend a maximum of 100 scope rules per scope.
Display groups 25 per site These are used for a grouped display of scopes through the user interface.
Crawl rules 10,000 per SSP We recommend a maximum 10,000 crawl rules irrespective of type.
Keywords 15,000 per site We recommend a maximum of 10 Best Bets and five synonyms per keyword.
Crawled properties 500,000 per SSP These are properties that are discovered during a crawl.
Managed properties 100,000 per SSP These are properties used by the search system in queries. Crawled properties are mapped to managed properties. We recommend a maximum of 100 mappings per managed property.
Authoritative pages 200 per relevance level This is the maximum number of sites in each of the four relevance levels.
Results removal 100 This is the maximum recommended number of URLs that should be removed from the system in one operation.
Crawl logs 50,000,000 Number of individual log entries in the crawl log.

The following table lists the recommended guidelines for logical architecture objects.


Logical architecture object

Guidelines for acceptable performance Notes
Shared Services Provider (SSP) 3 per farm (20 per farm maximum)  
Zone 5* per farm The number of zones defined for a farm is hard coded to 5.
Web application 99 per SSP This limit includes the number of Web applications on child farms consuming resources on this SSP.
Internet Information Services (IIS) application pool 8 per Web server Maximum number is determined by hardware capabilities.
Site collection 50,000 per Web application  
Content database 100 per Web application  
Site collection 50,000 per database  

The following table lists the recommended guidelines for physical objects.


Physical object

Guidelines for acceptable performance Notes
Index servers 1 per SSP*  
Application servers running Excel Calculation Services No limit  
Query servers No limit Because 100 content databases are supported for each query server, the number of query servers required per farm is based on the number of content databases in the farm. For example, if there are 500 content databases in your farm, you will need at least 5 query servers.
Web server/database server ratio 8 Web servers per database server The scale out factor is dependent upon the mix of operations.
Web server/domain controller ratio 3 Web servers per domain controller Depending on how much authentication traffic is generated, your environment may support a greater number of Web servers per domain controller.

SPSiteDataQuery example

on Wednesday, December 2, 2009

I have been playing with the SPSiteDataQuery a fair bit recently and thought it would be interesting to post some of the results.

When using the SPSiteDataQuery to perform a search there are four main properties you are going to set which determine the results you will get. If you have seen my previous post (XML results using SPSiteDataQuery in SharePoint) you will have seen that they are Lists, Query, Webs and ViewFields.

If you read nothing else then remember this...If you make a mistake in the Webs or Lists properties, invalid XML or invalid attributes, the SPSiteDataQuery will fall back to it's default behavior and will not throw an error!! Knowing this can save a lot of time...ensure your properties are correctly formatted.

So, assuming the basic setup is

SPSiteDataQuery q = new SPSiteDataQuery();
q.Lists = "<Lists BaseType='1'/>";
q.Query = "<Where><Gt><FieldRef Name='ID' /><Value Type='Number'>0</Value></Gt></Where>";
q.Webs = "<Webs Scope='SiteCollection' />";
q.ViewFields = "<FieldRef Name='Title' /><FieldRef Name='ID' />"';
q.RowLimit = 10;

Here are the changes you can make to achieve different result sets and tips as to why the query could be failing.

 

The Webs Property

There are basically three different values for this...


"<Webs Scope='SiteCollection' />" This will search the entire site collection no matter which web you use to execute the query.
"<Webs Scope='Recursive' />" This will search the web on which you execute the query and recurse through any child webs.

"" If you leave it blank then it will only search the web on which you execute the query. No child webs will be queried. This is important as I have read on several other sites that this is not possible with SPSiteDataQuery, but it is!!

I would also point out that that if you get anything wrong with this property SharePoint will not throw an error, it will just default to the blank behavior...It will only search the web on which you executed the query. This is an important point as "<Webs scope='Recursive' />"  or "<Webs Scope='recursive' />" (small 's' in Scope and small 'r' in recursive) look OK but are actually invalid and the query will default to only the current web.

 

The Lists Property

This defines what type of document libraries and lists WSS will search for your items. You can specify the exact type of list, the base type or even specific lists. Examples of the Lists property are...

"<Lists BaseType='1'/>" As above, this will search all lists which are based on a 'Document Library. This is useful if you only want to find documents. Other values for BaseType include...

0 - Generic list - This will search all lists and not document libraries.
1 - Document Library
3 - Discussion Forum
4 - Vote or Survey
5 - Issues list

(no, I don't know what happened to number 2!!)

I should also point out that the default is to search BaseType = '0' , and so if you do not set or make a mistake in the XML only lists will be searched.

"<Lists ServerTemplate='850'/>" This will limit the search to only a particular list template (850 is the Pages template in a publishing site). The number is fairly random and is defined in the list definition. I haven't needed to look at them as yet so I don't know a better way than looking in the definitions in the FEATURES folder for SharePoint. If you make a mistake with this property it will revert to the default.

Another options is Hidden, which determines if hidden lists or document libraries are searched. This an additional attribute and would be used like this...

"<Lists ServerTemplate='850' Hidden='TRUE'/>"

The MaxListLimit attribute specifies the total number of lists to search. You will receive an exception if the query exceeds the MaxListLimit. The default amount is 1000 and by setting this to 0 you can search everything. So the following would only search the first 50 lists...

"<Lists BaseType='1' MaxListsLimit='50'/>"

Another thing you can do with the Lists property is to query specific lists. This can be done by specifying the Guid of the list you want to search. An example would be...

"<Lists><List ID="129AB4CAE-12EF-9871-DE45-F34A180D3EAB5"/></Lists>"

You would obviously need to know the Guid of the lists you wish to query before creating this property.

 

The ViewFields property

The ViewFields property specifies the fields (columns), that will be returned in the query. This is very similar to SQL and you should ensure that you specify any fields that you may wish to use in you Where or OrderBy part of the query.

Things to point out here is that that you can specify the ID(Guid) of the property or the name of the property...this is the Internal Name, not the name you may see in the UI. For example the standard publishing field "Image Caption" would become "PublishingImageCaption" as that is it's internal name.

So, to add the "Image Caption" filed to the results we would need...

"<FieldRef Name='Title' /><FieldRef Name='ID' /><FieldRef Name='PublishingImageCaption' />"

Another thing to remember is that not all lists or documents libraries contain the same fields. If you are not worried about a particular field and want the item returned whether the field (column) exists or not the you can set Nullable to true. So if we have some items which may not have an 'Image Caption' column then we could use...

"<FieldRef Name='Title' /><FieldRef Name='ID' /><FieldRef Name='PublishingImageCaption' Nullable='TRUE'/>"

and this would still find those items without an 'Image Caption' column (field).

 

The Query Property

This property will allow you to bot limit and order you results. You can do both or just one, but it is similar to SQL in what you can do. There is a lot to this, but I will give a couple of samples...

Querying by date...

string sLastWeek = SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Today.AddDays(-1));
q.Query = "<Where><Gt><FieldRef Name='Created'><Value Type='DateTime'>" + sLastWeek + "</Value></Gt></Where>";

This will find items created within the last week. The <Gt> denotes 'Greater Than', you could also use <Gte>, <Lt> or <Eq>. These can be combined to create more complex queries.

q.Query = "<OrderBy><FieldRef Name='Title' Ascending='FALSE'></OrderBy>";

This will order the items descending by the title (Z-A).

q.Query = "<Where><Gt><FieldRef Name='Created'><Value Type='DateTime'>" + sLastWeek + "</Value></Gt></Where><OrderBy><FieldRef Name='Title' Ascending='FALSE'></OrderBy>";

This is a combination of the above...items created in the last week ordered Z-A.

Finally, make sure you set the RowLimit property...you may not get any results otherwise!!