How to disable a ribbon button when a folder is selected

I have added a new button to the SharePoint ribbon for document libraries. This all works well and the button is enabled / disabled depending on the number of items selected... fine!

I want to improve this by disabling the button when a folder is selected similar to how the standard SharePoint 'email a link' button works. Can anyone offer any advice on how to approach this? I have Googled around, but have not been able to find anything.

The code I currently have is as follows:

  <CustomAction      Id="Muhimbi.SharePoint.DocumentConverter.PDF.Ribbon.Documents.Copies.Controls.ConvertAndDownload.Action"      Location="CommandUI.Ribbon"      RegistrationType="ContentType"      RegistrationId="0x0101"      >      <CommandUIExtension>        <CommandUIDefinitions>          <CommandUIDefinition            Location="Ribbon.Documents.Copies.Controls._children">            <Button Id="Muhimbi.SharePoint.DocumentConverter.PDF.Ribbon.Documents.Copies.Controls.ConvertAndDownload.Button"                    Command="Muhimbi.SharePoint.DocumentConverter.PDF.Ribbon.Documents.Copies.Controls.ConvertAndDownload.Button.Command"                    Image16by16="/_layouts/images/Muhimbi.PDFConverter/pdf16.gif"                    Image32by32="/_layouts/images/Muhimbi.PDFConverter/pdf32.gif"                    LabelText="$Resources:ecb_title;"                    Sequence="12"                    TemplateAlias="o1" />          </CommandUIDefinition>        </CommandUIDefinitions>        <CommandUIHandlers>          <CommandUIHandler            Command="Muhimbi.SharePoint.DocumentConverter.PDF.Ribbon.Documents.Copies.Controls.ConvertAndDownload.Button.Command"            CommandAction="javascript:window.location='{SiteUrl}/_layouts/Muhimbi.PDFConverter/Convert.aspx?action=ConvertAndDownload&amp;ListId={ListId}&amp;ItemId=' + SP.ListOperation.Selection.getSelectedItems()[0].id + '&amp;Source=' + window.location"            EnabledScript="javascript:function singleEnable()            {              var items = SP.ListOperation.Selection.getSelectedItems();              var ci = CountDictionary(items);              return (ci == 1);            }            singleEnable();" />        </CommandUIHandlers>      </CommandUIExtension>    </CustomAction>  Answers: 

Use the fsObjType property:

EnabledScript="javascript:    var items = SP.ListOperation.Selection.getSelectedItems();    (items.length == 1 &amp;&amp; items[0].fsObjType == 0);"  



How To Send Email with SPUtility in Sharepoint

There is no doubt that email is a key functionality in today's enterprise. In organizations where SharePoint 2007 has also become a key collaboration platform you'll increasingly find situations where you need to send email from within the SharePoint environment. This article shows how to accomplish that, using the SPUtility class'sSendEmailmethod.

There are many scenarios where you might want to send an email notification.

In this scenario, whenever a document gets uploaded to the document library, the system first applies some business rules and logic, and then notifies users interested in that document by email. Although this is a simple scenario, it shows clearly how email is an important component of today's organizational strategies. As a SharePoint developer, that means you need a quick and easy way to send email.

Traditionally developers have used the SMTP class in ASP.NET to send email; it's quite powerful and provides fine granular control over the contents. But to use it, you need to add appropriate references and set the various properties. When your requirements are simple—such as simply sending some brief text notifications, or when email is only part of some other automated process or workflow, you may want to look at the SPUtility class'sSendEmailmethod instead. While it doesn't have the power of ASP.NET's SmtpClient class, it's much easier to use. The following example sends email usingSPUtililty.SendEmail:

private Boolean SendEmail() {   try   {     bool flag = false;     SPSecurity.RunWithElevatedPrivileges(       delegate()     {       using (SPSite site = new SPSite(         SPContext.Current.Site.ID,         SPContext.Current.Site.Zone))       {         using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))         {           flag = SPUtility.SendEmail(web, true, true,                                       "TO@example.com",                                      "Subject",                                      "This is a sample email Body");         }       }     });     return flag;   }   catch (System.Exception exp)   {     // Do some error logging     return false;   } }  

The first thing to remember is that you need to use the Microsoft.SharePoint.Utilities namespace, which contains the SPUtility class that exposes theSendEmailmethod. Note thatSendEmailoccupies only one line in the preceding code. You should also note that you may need to elevate privileges, because the current user context may not have sufficient permission to send email.

There areseveral overloads of theSendEmailmethod. The parameters for the version shown are an SPWeb object (web), followed by two Boolean parameters:AppendHtmlTags, which whentrueappends an HTML tag to the message,falseotherwise, andHtmlEncode, which whentrueencodes the message and replace characters in HTML tags with entities. The last three parameters are strings that correspond to the email'sTo,Subject, andBodyfields, respectively.

TheSendEmailmethod returns a Booleantruefor success orfalseif the send attempt failed.

As you can see, sending basic email usingSendEMailis straightforward; however, note these key considerations:

  • Attachments are not allowed.
  • By default, the message body cannot exceed 2048 characters.SendEMailwill truncate all characters beyond 2048. The workaround is to ensure that nosingle linein your message body exceeds 2048 characters. Simply add newline characters as needed to keep the lines under the 2048 character limit.
  • By default, theFromaddress is always set to the value from the Central Administration Outbound Mail Sender Address field.


How To Send Email with SPUtility in Sharepoint

There is no doubt that email is a key functionality in today's enterprise. In organizations where SharePoint 2007 has also become a key collaboration platform you'll increasingly find situations where you need to send email from within the SharePoint environment. This article shows how to accomplish that, using the SPUtility class's SendEmail method.

There are many scenarios where you might want to send an email notification.

In this scenario, whenever a document gets uploaded to the document library, the system first applies some business rules and logic, and then notifies users interested in that document by email. Although this is a simple scenario, it shows clearly how email is an important component of today's organizational strategies. As a SharePoint developer, that means you need a quick and easy way to send email.

Traditionally developers have used the SMTP class in ASP.NET to send email; it's quite powerful and provides fine granular control over the contents. But to use it, you need to add appropriate references and set the various properties. When your requirements are simple—such as simply sending some brief text notifications, or when email is only part of some other automated process or workflow, you may want to look at the SPUtility class's SendEmail method instead. While it doesn't have the power of ASP.NET's SmtpClient class, it's much easier to use. The following example sends email using SPUtililty.SendEmail:

private Boolean SendEmail() {   try   {     bool flag = false;     SPSecurity.RunWithElevatedPrivileges(       delegate()     {       using (SPSite site = new SPSite(         SPContext.Current.Site.ID,         SPContext.Current.Site.Zone))       {         using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))         {           flag = SPUtility.SendEmail(web, true, true,                                       "TO@example.com",                                      "Subject",                                      "This is a sample email Body");         }       }     });     return flag;   }   catch (System.Exception exp)   {     // Do some error logging     return false;   } }  

The first thing to remember is that you need to use the Microsoft.SharePoint.Utilities namespace, which contains the SPUtility class that exposes the SendEmail method. Note that SendEmail occupies only one line in the preceding code. You should also note that you may need to elevate privileges, because the current user context may not have sufficient permission to send email.

There are several overloads of the SendEmail method. The parameters for the version shown are an SPWeb object (web), followed by two Boolean parameters: AppendHtmlTags, which when true appends an HTML tag to the message, false otherwise, and HtmlEncode, which when true encodes the message and replace characters in HTML tags with entities. The last three parameters are strings that correspond to the email's To, Subject, and Body fields, respectively.

The SendEmail method returns a Boolean true for success or false if the send attempt failed.

As you can see, sending basic email using SendEMail is straightforward; however, note these key considerations:

  • Attachments are not allowed.
  • By default, the message body cannot exceed 2048 characters. SendEMail will truncate all characters beyond 2048. The workaround is to ensure that no single line in your message body exceeds 2048 characters. Simply add newline characters as needed to keep the lines under the 2048 character limit.
  • By default, the From address is always set to the value from the Central Administration Outbound Mail Sender Address field.


How To Send Email with SPUtility in Sharepoint

There is no doubt that email is a key functionality in today's enterprise. In organizations where SharePoint 2007 has also become a key collaboration platform you'll increasingly find situations where you need to send email from within the SharePoint environment. This article shows how to accomplish that, using the SPUtility class's SendEmail method.

There are many scenarios where you might want to send an email notification.

In this scenario, whenever a document gets uploaded to the document library, the system first applies some business rules and logic, and then notifies users interested in that document by email. Although this is a simple scenario, it shows clearly how email is an important component of today's organizational strategies. As a SharePoint developer, that means you need a quick and easy way to send email.

Traditionally developers have used the SMTP class in ASP.NET to send email; it's quite powerful and provides fine granular control over the contents. But to use it, you need to add appropriate references and set the various properties. When your requirements are simple—such as simply sending some brief text notifications, or when email is only part of some other automated process or workflow, you may want to look at the SPUtility class's SendEmail method instead. While it doesn't have the power of ASP.NET's SmtpClient class, it's much easier to use. The following example sends email using SPUtililty.SendEmail:

private Boolean SendEmail() {   try   {     bool flag = false;     SPSecurity.RunWithElevatedPrivileges(       delegate()     {       using (SPSite site = new SPSite(         SPContext.Current.Site.ID,         SPContext.Current.Site.Zone))       {         using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))         {           flag = SPUtility.SendEmail(web, true, true,                                       "TO@example.com",                                      "Subject",                                      "This is a sample email Body");         }       }     });     return flag;   }   catch (System.Exception exp)   {     // Do some error logging     return false;   } }  

The first thing to remember is that you need to use the Microsoft.SharePoint.Utilities namespace, which contains the SPUtility class that exposes the SendEmail method. Note that SendEmail occupies only one line in the preceding code. You should also note that you may need to elevate privileges, because the current user context may not have sufficient permission to send email.

There are several overloads of the SendEmail method. The parameters for the version shown are an SPWeb object (web), followed by two Boolean parameters: AppendHtmlTags, which when true appends an HTML tag to the message, false otherwise, and HtmlEncode, which when true encodes the message and replace characters in HTML tags with entities. The last three parameters are strings that correspond to the email's To, Subject, and Body fields, respectively.

The SendEmail method returns a Boolean true for success or false if the send attempt failed.

As you can see, sending basic email using SendEMail is straightforward; however, note these key considerations:

  • Attachments are not allowed.
  • By default, the message body cannot exceed 2048 characters. SendEMail will truncate all characters beyond 2048. The workaround is to ensure that no single line in your message body exceeds 2048 characters. Simply add newline characters as needed to keep the lines under the 2048 character limit.
  • By default, the From address is always set to the value from the Central Administration Outbound Mail Sender Address field.


Userful 7 Projects for SharePoint 2010 on CodePlex

Popular software products usually benefit from strong technical communities. That is certainly the case with SharePoint. SharePoint 2007 saw a rise in the number of open source projects on sites such as CodePlex to fill in the gaps of what is not offered out of the box. With SharePoint 2010, many more features were included in the base product and the development tools such as Visual Studio, but there are still some very useful tools on CodePlex to help you get more out of SharePoint 2010.

Some of the SharePoint 2010 projects on CodePlex are geared toward farm administrators, site collection administrators, and power users, but the majority of the projects seem to be focused on developers. I will present projects for all four audiences and identify for whom it was intended.

SharePoint Manager 2010

SharePoint Manager 2010 is useful for both SharePoint farm administrators and developers alike. If you are a farm administrator, the tool will allow you to browse the configuration properties of your SharePoint servers and sites. In many cases, you can change the properties right from within the application. For developers, this tool helps you become more familiar with the objects in a SharePoint farm so that you will know what is available to set programmatically.

SPServices jQuery Library for SharePoint

The SPServices jQuery Library for SharePoint is a real gem. This project is ideal for SharePoint power users or traditional web developers who do not have deep SharePoint development experience using Visual Studio. The idea of the project is to wrap calls to the SharePoint web services so that they are easily called by someone who is familiar with jQuery (a JavaScript framework). The library includes features and behaviors that are not available out of the box in SharePoint. For example, if you want to filter a drop down list based on the criteria that was entered in another drop down list, this tool will allow you to do so through some easy to follow JavaScript code.

SharePoint Content Deployment Wizard

The SharePoint Content Deployment Wizard has proven to be useful time and time again. From migrating content during server upgrades, to refreshing content from your production to your development farm, this tool is a time saver. You can export SharePoint content at the site collection level, site, list or even individual list items, and then import them on a target server or site.

SharePoint 2010 Bulk Document Importer

If you need to import documents from a file share to SharePoint, the SharePoint 2010 Bulk Document Importer may be the tool for you. Why not just drag and drop files using the explorer view? This tool provides useful features that are an advantage over the out of the box document upload methods. For example, if you drag and drop a file from the file system into a document library, the name of the logged on user will be used for the last modified by. With this tool, the last modified information from the file system is retained. Other useful features include: logging, renaming illegally named files, and moving successfully migrated files to an archive folder.

SharePoint Log Viewer

The SharePoint Log Viewer has got to be one of the handiest ways to monitor SharePoint's Unified Logging Service (ULS) logs, and it is available for free. You can filter the logs by event id, level or category. In addition, you can set up email alerts to notify you if a certain severity of error is logged. If you are not a fan of receiving emails for problems logged on your server, then a less obtrusive system tray notification option is included.

WinForm SharePoint List Item Editing Tool

Use the WinForm SharePoint List Item Editing Tool if you want to work with SharePoint lists in batch. Without the need to create additional datasheet views, you can use this tool from your workstation to add and remove columns to a grid view. You can paste data from Excel and perform other batch functions such as checking in a selection of documents or importing a batch of documents. If you have event receivers on a list that fire when an item is added or modified, this tool will allow you to suppress those events when working in batch mode.

SPUtility.js

Still in alpha mode, the SPUtility.js project already offers features that are useful to power users and web developers. Unlike the SPServices jQuery Library for SharePoint, these JavaScript wrappers for SharePoint web services are based on the Prototype.js JavaScript framework and not on jQuery. The ideal use for this project is to get and set properties on the out of the box SharePoint list forms. You may get and set the value of a field. You may also change the properties of a field to make it read only, editable, visible, or hidden.

There are CodePlex projects for SharePoint that are worthy of mention, and more projects will likely surface in the near future. I encourage you to take a look at these projects and see how you may benefit from them on your SharePoint 2010 projects.



Extend Content Query Web Part via Code in SharePoint 2010

I'm trying to understand the mechanism to extend the cqwp via code.

It may be hard to believe but I couldn't find a single article to create a web part inherited from content by query web part.

What I need to do, is to type the listname in the web part properties. Then all the groupings, sorting and the query will be implemented via code, that is in the extended web part.

I've read waldek's posts but they are a bit advanced to use as a cheat sheet.

Msdn's samples show the customization of itemstyle and setting queryoverride over the webpart properties toolbar. I need to set it via code.

Note:If that's not the way to customize cqwp, let me know. My purpose is to put the wp in the masterpage and set the listname and wait for the results to show(:

I've tried to set the listguid and queryoverride via code through OnInit and ModifyXsltArgument methods seperately. Nothing returned, and when I export the wp, the listguid and queryoverride seems not set.

Solution:

To inherit the ContentQueryWebPart just do this:

using System; using System.ComponentModel; using Microsoft.SharePoint.Publishing.WebControls; using Microsoft.SharePoint; using Microsoft.Office.Server.UserProfiles;  namespace YOURNAMESPACE {     [ToolboxItemAttribute(false)]     public class CustomContentQueryWebPart : ContentByQueryWebPart     {         protected override void OnLoad(EventArgs e)         {             try             {                 //Reemplazamos [UserContext:<field>] por su valor                 string val, field;                 UserProfile userProfile = getCurrentUserProfile();                  val = this.FilterValue1;                 if (val.StartsWith("[UserContext:") && val.EndsWith("]"))                 {                     field = val.Substring(13, val.Length - 14);                     this.FilterValue1 = userProfile[field].Value.ToString();                 }                  val = this.FilterValue2;                 if (val.StartsWith("[UserContext:") && val.EndsWith("]"))                 {                     field = val.Substring(13, val.Length - 14);                     this.FilterValue2 = userProfile[field].Value.ToString();                 }                  val = this.FilterValue3;                 if (val.StartsWith("[UserContext:") && val.EndsWith("]"))                 {                     field = val.Substring(13, val.Length - 14);                     this.FilterValue3 = userProfile[field].Value.ToString();                 }             }             catch (Exception ex) { }             finally             {                 base.OnLoad(e);             }         }          private UserProfile getCurrentUserProfile()         {             SPUser user = SPContext.Current.Web.CurrentUser;             //Create a new UserProfileManager             UserProfileManager pManager = new UserProfileManager();             //Get the User Profile for the current user             return pManager.GetUserProfile(user.LoginName);         }     } } 

In this example, I just added a filter to get a field from UserProfile like the original webpart does with querystring. What do you need exactly?



Treeview Control in Sharepoint 2010

In this post you will learn how to Programmatically use the Treeview control in Sharepoint 2010.

At First, we will create an application page in VS 2010 to contain a drop-down list bind to all the Navigation Providers in SharePoint 2010 and a TreeView Control to display the selected navigation providers in a Treeview hierarchy. Lets follow the Steps -

Steps -

1. Create a new Application Page in Vs 2010.
2. Add the below code to the aspx of the application page

<%@ Page Language="C#" AutoEventWireup="true" DynamicMasterPageFile="~masterurl/default.master"
CodeFile="NavigationProviders.aspx.cs" Inherits="NavigationProviders" CodeFileBaseClass="Microsoft.SharePoint.WebControls.LayoutsPageBase" %>

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<asp:DropDownList id="ddlNavProviders" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ddlNavProviders_SelectedIndexChanged" />
<asp:TreeView id="navTreeView" runat="server"></asp:TreeView>
< /asp:Content>

3. Add the Code behind – The code-behind class first initializes DropDownList with all the navigation providers defined in web.config. By selecting a navigation provider, the SiteMapDataSource pointing to the selected provider is bound to the TreeView.

using System;
using System.Web;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
public partial class NavigationProviders : LayoutsPageBase
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Init the DropDown element with all available navigation providers
ddlNavProviders.DataSource = SiteMap.Providers;
ddlNavProviders.DataTextField = "Name";
ddlNavProviders.DataBind();
}
}

protected void ddlNavProviders_SelectedIndexChanged(object sender,EventArgs args)
{
// Bind the selected navigation provider to the TreeView
SiteMapDataSource ds = new SiteMapDataSource();
ds.Provider = SiteMap.Providers[ddlNavProviders.SelectedItem.Text];
navTreeView.DataSource = ds;
navTreeView.DataBind();
}
}





Subclassing Content Query Web Part to override CAML query

The Content Query Web Part (CQWP) in MOSS is one of the popular out-of-the-box Publishing components which is used in content management sites, allowing you to get results from different sources.

But sometimes out of the box functionality is not enough to meet your requirements, and you need to customize CQWP. There are several resources describing how to do this - 1, 2, 3, 4

The most important features which are missed in CQWP are:

  • overriding query to use custom CAML
  • enabling web-part connections

To implement these functionality you need to subclass ContentByQueryWebPart class and override several methods.

Below I will describe what exactly need to be done to achieve desired behaviour.

Query Override

To have custom CAML query in your Web part you need to override CreateChildControls base method. You can find samples how to do this in the references above, but it's done so implicitly, that you can easily spend hours to find out why you code doesn't work and gives you different errors

The crucial part is in the way sending the query to the base class within overrided CreateChildControls

   1: protected override void CreateChildControls()
   2: {
   3:     this.QueryOverride = customQueryString;
   4:  
   5:     base.CreateChildControls();
   6:  
   7:     QueryOverride = string.Empty;
   8:  
   9:     CommonViewFields = string.Empty;
  10: }

First, you need to set your custom query to the "this.QueryOverride" to inform base class about query - line 3

Second, call base CreateChildControls() allowing your query being executed - line 5

Third and last - CLEAN query and view fields properties - line 7,9. Without this step you will get errors when open your Web Part in edit mode

Enabling Connection

The Content Query WP doesn't accept any connections by default. You need to implement this too. Everything you need to to is just add ConnectionConsumer attribute. But trick in setting the right attribute which is used in Parameter dialog box, when you connect two web-parts.

   1: [ConnectionConsumer("Another WebPart", "IFilterValues", AllowsMultipleConnections = true)]
   2: public void SetConnectionInterface(IFilterValues filterProvider)
   3: {
   4:     if (filterProvider != null)
   5:     {
   6:         // save provider with values
   7:         providerValues = filterProvider.ParameterValues;
   8:         _filterProviders.Add(filterProvider);  // variable declaration is List<IFilterValues> _filterProviders = new List<IFilterValues>();
   9:         List<ConsumerParameter> parameters = new List<ConsumerParameter>();
  10:         
  11:         // add params
  12:         parameters.Add(new ConsumerParameter("param1",
  13:                 ConsumerParameterCapabilities.SupportsSingleValue |
  14:                 ConsumerParameterCapabilities.SupportsEmptyValue));
  15:         parameters.Add(new ConsumerParameter("param2",
  16:                 ConsumerParameterCapabilities.SupportsMultipleValues |
  17:                 ConsumerParameterCapabilities.SupportsAllValue |
  18:                 ConsumerParameterCapabilities.SupportsEmptyValue));
  19:  
  20:         filterProvider.SetConsumerParameters(new ReadOnlyCollection<ConsumerParameter>(parameters));
  21:  
  22:         }
  23: }

Method name can be any, but pay attention which provider you are using . WebPart providers send data via different provider interfaces, for example when you are working with Filtering web parts (like "Current User Filter" web part) then you need to "listen" your incoming connections via IFilterValues (thx Mutaz for this findings), for other WB it could be IWebPartField or IWebPartRow.

If you are expecting to get data from WP via unsupported provider you connection link will be dimmed

Practical Sample

@d2design kindly asked to provide practical sample, for example how to use current user as a keyword :)

Actually, it's good example which shows how use both features I described.

To do this you need to have:

  1. ShareServices (SSP) with UserProfile, where current userName is stored
  2. "Current User Filter" WebPart, to get the userName from SSP. It returns you logged user name by default (not necessary actually, as well as SSP, because you could resolve you user name via standard asp.net User class when construct custom query)
  3. Enable WebPart connections as I described above. You need to use IFilterValue interface for "Current User Filter" and store your incoming user name in variable.
  4. Override query to include your userName in resulted custom query.

TIPS:

  1. When you are quering content which is not published and approved (like pages) you wont be able to see that content on the page in final view. You data will be available in page edit mode only, because they are treated as "draft" data.
  2. <OrderBy>CAML tag is not parsed by CQWP, you need to remove it from your query and set the related order field of CQWP class




poor performance on people picker search in SharePoint 2010

Consider this scenario:

You go to the people picker to search for let's say: "User42". You wait for about more than 3.5 min. until the results are displayed.
You'd now check if there is a general problem and trying it again with a simple repro on the file system as follows

- chose any folder on your hard disk, right-click and chose "properties".
- "add" the wanted User as you would like to do it on granting permissions to this folder.
- Note, that this is taking less than a second(!) to resolve and adding the named User, how this?

So on setting the ULS logging to "verbose" level and retry the peoplepicker search, we will find some interesting hints like this in our logs:

[…]
01.31.2011 15:50:13.98 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq2 Verbose SearchFromGC name = corp.lan. returned. Result count = 0 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:50:13.98 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq1 Verbose SearchFromGC name = contoso.com. start 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:50:30.12 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq3 Verbose SearchFromGC name = contoso.com. Error Message: A local error has occurred. 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:50:30.12 w3wp.exe (0x1010) 0x163C SharePoint Foundation General 7fbh Verbose Exception when search "user42" from domain "contoso.com". Exception: "A local error has occurred. ", StackTrace: " at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at […]

01.31.2011 15:50:30.12 w3wp.exe (0x1010) 0x163C SharePoint Foundation General 72e7 Medium Error in searching user 'user42' : System.DirectoryServices.DirectoryServicesCOMException (0x8007203B): A local error has occurred. at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at […]

01.31.2011 15:50:30.12 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq1 Verbose SearchFromGC name = de-corpx.com. start 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:12.95 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq3 Verbose SearchFromGC name = de-corpx.com. Error Message: The server is not operational. 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:12.95 w3wp.exe (0x1010) 0x163C SharePoint Foundation General 7fbh Verbose Exception when search "user42" from domain "de-corpx.com". Exception: "The server is not operational. ", StackTrace: " at […]

01.31.2011 15:51:12.95 w3wp.exe (0x1010) 0x163C SharePoint Foundation General 72e7 Medium Error in searching user 'user42' : System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational. at […]

01.31.2011 15:51:13.08 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq2 Verbose SearchFromGC name = my-group.biz. returned. Result count = 0 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:13.08 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq1 Verbose SearchFromGC name = org-it.biz. start 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:13.27 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq4 Verbose GetAccountNameFromSid "0x0105000000000005150000008AA7323F23F3F66375B9755494000400" start 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:13.28 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq5 Verbose GetAccountNameFromSid "0x0105000000000005150000008AA7323F23F3F66375B9755494000400" returned. returnValue=True 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:13.28 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq2 Verbose SearchFromGC name = org-it.biz. returned. Result count = 1 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:13.28 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq1 Verbose SearchFromGC name = xx-ext.biz. start 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:13.52 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq2 Verbose SearchFromGC name = xx-ext.biz. returned. Result count = 0 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:13.52 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq1 Verbose SearchFromGC name = ap-lan.biz. start 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:51:56.33 w3wp.exe (0x1010) 0x163C SharePoint Foundation Performance ftq3 Verbose SearchFromGC name = ap-lan.biz. Error Message: The server is not operational. 21e10f56-2f45-4a29-a53c-4fda5da9f117
01.31.2011 15:53:15.22 w3wp.exe (0x1010) 0x163C SharePoint Foundation General 72e7 Medium Error in searching user 'user42' : System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational. at
[…]


CAUSE:

For any given search string, i.e. "User42" (which is NOT typed in as "Domain\username" or as UPN "user42@mydomain.com") the Query fetches the account details (SearchFromGC) for the user.

The GetAccountName() function is then used to convert the SID returned by the LDAP query.
The GetAccountName() results in LSASS calling LsarLookupSids3 (when using People Picker) OR both LsaLookupNames4 + LsarLookupSids3 (when using "Check Names").

So we see that we do get the result back from LDAP with the result set and then we use that result set's SID to get the account name in the format DOMAIN\USERLOGIN. The LDAP resultset has this information in the LDAP format, but not in the expected format for SharePoint. This is why we call GetAccountName() to resolve the SID into the Account name.

This process takes a long time and impacts the performance for People Picker / CheckNames function as well as in addition waiting for each timeout on not reachable DC's.

So by using "Isolated Account Names" on peoplepicker search, performance decreases as the number of trusted domains increases…
See more on http://support.microsoft.com/kb/818024

RESOLUTION/WORKAROUND:

Use the stsadm commands for setting the properties to be limited on a particular Domain (where the user lives) and the specific Domain under your Forest on a multi trusted AD environment.

stsadm -o setproperty -url http://<WebAppName> -pn peoplepicker-distributionlistsearchdomains -pv <domainname>

stsadm –o setproperty –pn peoplepicker-searchadforests –pv domain:<domainname> -url http://<WebAppName>

Note Note:

By default, SharePoint talks to the domain controller for the domain in which SharePoint was installed and all trusted domains for two-way trusted domains.

Remarks:

The above commands will enable a limited search against a dedicated domain where the wanted user account resides.
So when having user accounts from other domains in addition, these domains must be also set according to the above command for each needed domain name.
This setting is a per web application setting as defined by the -url parameter and must be also repeated for each web application further.
So by design, SharePoint will behave as of the above description but on forcing only to use the pure ldap results and defining the requested domain explicitly,
we can significant increase the performance on people picker search results near to less than 2 seconds!

If you're having a "one-way-trust", then you need to run additionally this command first:
stsadm –o setapppassword -password <SomeKey>

see more details here: http://technet.microsoft.com/en-us/library/cc263460(office.12).aspx



SharePoint 2010: Programatically Retrieve Credentials from the Secure Store Service

SharePoint 2010′s Secure Store Service provides a way to map credentials and delegate access to remote resources. You may already be familiar with the MOSS 2007 Single Sign-on Shared Service, which was the former equivalent. The Secure Store Service integrates seemlessly with Business Connectivity Services (BCS), but it also features an API that can be taken advantage of within custom development projects. This makes the service an attractive option for storing sensitive configuration data such as connection strings, Web service credentials, etc.

The Secure Store Service allows us to create Target Applications which house sets of credentials. The two main types are Individual and Group applications, Individual meaning credentials are mapped to individual users, and Group meaning all users share the same set of credentials.

While the raw API isn't very intuitive, its design was likely intentional (additional security by obfuscation). With a little marshalling help from our interop library friends, we are able to retrieve credentials (provided the appropriate permissions to the target application).

To begin, we need to reference a couple of assemblies.

Microsoft.BusinessData.dll

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.BusinessData.dll

Microsoft.Office.SecureStoreService.dll

C:\Windows\assembly\GAC_MSIL\Microsoft.Office.SecureStoreService\14.0.0.0__71e9bce111e9429c\Microsoft.Office.SecureStoreService.dll

And now for the reason you came to this post … the code

using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Security; using Microsoft.BusinessData.Infrastructure.SecureStore; using Microsoft.Office.SecureStoreService.Server; using Microsoft.SharePoint;   namespace Trentacular.SharePoint.Util {     public static class SecureStoreUtils     {         public static Dictionary<string, string> GetCredentials(string applicationID)         {             var serviceContext = SPServiceContext.Current;             var secureStoreProvider = new SecureStoreProvider { Context = serviceContext };             var credentialMap = new Dictionary<string, string>();               using (var credentials = secureStoreProvider.GetCredentials(applicationID))             {                 var fields = secureStoreProvider.GetTargetApplicationFields(applicationID);                 for (var i = 0; i < fields.Count; i++)                 {                     var field = fields[i];                     var credential = credentials[i];                     var decryptedCredential = ToClrString(credential.Credential);                       credentialMap.Add(field.Name, decryptedCredential);                 }             }               return credentialMap;         }           public static string ToClrString(this SecureString secureString)         {             var ptr = Marshal.SecureStringToBSTR(secureString);               try             {                 return Marshal.PtrToStringBSTR(ptr);             }             finally             {                 Marshal.FreeBSTR(ptr);             }         }     } }




FluentSP – The Fluent SharePoint API

Download FluentSP 1.0 from Codeplex.com

Once you are doing a lot of SharePoint programming you know you often have to write lengthy pieces of code to implement simple tasks like querying SharePoint lists. Nowadays you can read a lot of fluent APIs or fluent interface. For instance, jQuery, a JavaScript library that had successfully introduced a fluent API to handle the hierarchical structure of the HTML documents.

Today, I want to introduce a small library I have developed, FluentSP, a modern fluent interface around the classic SharePoint 2010 API. By using FluentSP instead of the classic SharePoint API, you will be able to chain methods and act on sets of items of the underlying SharePoint objects.

What is a fluent API?
Checkout this CodeProject article A Look at Fluent APIs and the Wikipedia article Fluent interface.

To start into the fluent API you call the Use() method on SPSite, SPWeb, SPWebCollection or SPListCollection. The Use() method is implemented as an extension method that will return the entry facade object (see facade table below). Another entry point to the fluent API is the static class SP with its static methods CurrentSite, CurrentWeb, CurrentLists or RootWebLists.

1 SPContext.Current.Site.Use()... // => Returns the SPSiteFacade as entry point
2
3 // OR:
4 SP.CurrentSite()... // => Returns the SPSiteFacade as entry point

Using the entry facade instance you can start chaining the available facade methods as follows:

1 SP.CurrentSite().Web("Home").List("Tasks").Items().ForEach(i => // Do something with the item i of type SPListItem...);
2
3 // OR:
4 SP.CurrentSite()
5 .Web("Home")
6 .List("Tasks")
7 .Items()
8 .ForEach(i => // Do something with...);

Each facade object is actually wrapping an underlying data item, for instance the SPSiteFacade class is the fluent wrapper of the SPSite class. Depending on what kind of facade methods you are calling the method is returning either the current facade instance (e.g., ForEach() or Where()) or the method is returning a new child facade object (e.g. Items()). During the process of chaining methods in such a way you will build up a tree or hierarchy of facade instances. In order to step back to the parent or previous facade instance you need to call the End() method:

1 site.Use()
2 .RootWeb()
3 .Site()
4 .End() // Returns SPWebFacade as parent facade
5 .Site()
6 .End() // Returns SPWebFacade as parent facade
7 .End(); // Returns SPSiteFacade as parent facade

FluentSP is currently missing a number of possible useful methods, but you can easily extend the FluentSP API with custom facade classes and extension methods, see below and source code for implementation examples.

Samples

1 SPSite site = SPContext.Current.Site;
2
3 // ----------------------------
4
5 // Outputs titles of all lists of the root web where the list title starts with T
6 site.Use().RootWeb().Lists().Where(l => l.Title.StartsWith("T")).ForEach(l => Console.WriteLine(l.Title));
7
8 // Outputs titles of all lists of the root web where the list title ends with a ts (using RegEx)
9 site.Use().RootWeb().Lists("ts$").ForEach(l => Console.WriteLine(l.Title)).Count(out c);
10
11 // Outputs titles of all lists of the root web in ascending order where the starts with T
12 site.Use().RootWeb().Lists().Where(l => l.Title.StartsWith("T")).OrderBy(l => l.Title).ForEach(l => Console.WriteLine(l.Title));
13
14 // Outputs titles of all lists of the root web in descending order where the starts with T
15 site.Use()
16 .RootWeb()
17 .Lists()
18 .Where(l => l.Title.StartsWith("T"))
19 .OrderByDescending(l => l.Title)
20 .ForEach(l => Console.WriteLine(l.Title));
21
22 // ----------------------------
23
24 // Delete all items in the Members list, then add 7 new members and then select and output
25 // the titles of a few of the newly created items
26 site.Use()
27 .RootWeb()
28 .List("Members")
29 .Do(w => Console.WriteLine("Deleting all members..."))
30 .Items()
31 .Delete()
32 .End()
33 .Do(w => Console.WriteLine("Adding all members..."))
34 .AddItems(7, (i, c) => i["Title"] = "Member " + c)
35 .Items()
36 .Skip(2)
37 .TakeUntil(i => ((string)i["Title"]).EndsWith("6"))
38 .ForEach(i => Console.WriteLine(i["Title"]));
39
40 // ----------------------------
41
42 // Search for lists that are created by specific a user and depending on the results
43 // displays different messages by calling the IfAny or IfEmpty methods
44 site.Use()
45 .RootWeb()
46 .Lists()
47 .ThatAreCreatedBy("Unknown User")
48 .IfAny(f => f.ForEach(l => Console.WriteLine(l.Title)))
49 .IfAny(l => l.Title.StartsWith("M"), f => Console.WriteLine("Lists found that starts with M*"))
50 .IfEmpty(f => Console.WriteLine("No lists found for user"))
51 .End()
52 .Do(w => Console.WriteLine("---"))
53 .Lists()
54 .ThatAreCreatedBy("System Account")
55 .IfAny(f => f.ForEach(l => Console.WriteLine(l.Title)));
56
57 // ----------------------------
58
59 var items = new List<SPListItem>();
60
61 // Query with Skip and TakeUnitl methods
62 site.Use().RootWeb().List("Members").Items().Skip(2).TakeUntil(i => i.Title.EndsWith("5")).ForEach(i => { items.Add(i); Console.WriteLine(i.Title); });
63
64 // Query with Skip and TakeWhile methods
65 site.Use()
66 .RootWeb()
67 .List("Members")
68 .Items()
69 .Skip(2)
70 .TakeWhile(i => i.Title.StartsWith("Member"))
71 .ForEach(i => { items.Add(i); Console.WriteLine(i.Title); })
72 .End()
73 .Items()
74 .Where(i => i.Title == "XYZ")
75 .ForEach(i => { items.Add(i); Console.WriteLine(i.Title); });
76
77 // ----------------------------
78
79 // Adds new items using the Do method with the passed facade object
80 site.Use()
81 .RootWeb()
82 .AllowUnsafeUpdates()
83 .List("Members")
84 .Do((f, l) => {
85 for(int c = 1; c <= 5; c++)
86 f.AddItem(i => i["Title"] = "Standard Member #" + c);
87 })
88 .AddItem(i => i["Title"] = "Premium Member")
89 .Items()
90 .OrderBy(i => i.Title)
91 .ForEach(i => Console.WriteLine(i["Title"]));

Extensibility Samples

1 // This sample is using the ThatAreCreatedBy extension method defined in Extensions.cs to show how to extend the fluent API
2 site.Use()
3 .RootWeb()
4 .Lists()
5 .ThatAreCreatedBy("System Account", "jbaurle")
6 .Count(c => Console.WriteLine("Lists found: {0}", c))
7 .ForEach(l => Console.WriteLine(l.Title));
8
9 // This sample uses the new SPWebApplicationFacade extenion defined in SPwebApplicationFacade.cs to show how to extend the fluent API
10 site.WebApplication.Use()
11 .Sites()
12 .ForEach(i => Console.WriteLine(i.Url));
13
14 // This sample uses an alternative implementation for SPSiteFacade defined in SPSiteFacadeAlternate.cs to show how to extend the fluent API
15 site.WebApplication.Use().WithFirstSite().DoSomething();
16 site.Use<SPSiteFacadeAlternate<BaseFacade>>().DoSomething();

The custom method ThatAreCreatedBy which is used in the first query of the extensibility samples is implemented as follows:

1 static class Extensions
2 {
3 public static SPListCollectionFacade<TParentFacade> ThatAreCreatedBy<TParentFacade>(this SPListCollectionFacade<TParentFacade> facade, params string[] names)
4 where TParentFacade : BaseFacade
5 {
6 // NOTE: This sample uses the GetCollection method of the given facade instance to retrieve the current
7 // collection and adds the its query (see LINQ Deferred Execution). The Set method updates the
8 // underlying collection. The GetCurrentFacade method will then return the current facade to allow
9 // method chaining.
10
11 if(names.Length > 0)
12 facade.Set(facade.GetCollection().Where(i => names.Contains(i.Author.Name)));
13
14 return facade.GetCurrentFacade();
15 }
16 }

For more samples and details check out the source code you can download from Codeplex.

Built-In Facades and Methods

See Codeplex