SharePoint Dragons

Nikander & Margriet on SharePoint

Optimize with Aptimize?

A long time ago, we did a SharePoint 2001 project (yep, the first version) where we needed to support 40.000 people. Really hard to do since at that time SharePoint could not scale out and everything including the datatabase (the Exchange-based web storage system or WSS) had to be located on a single server. We used a 3rd party performance optimizer tool that really helped a lot.

We haven’t really kept track of such tools, but here’s one you can use for SharePoint 2010 today: Aptimizer ( http://www.riverbed.com/us/products/stingray/stingray_aptimizer.php ). It’s always nice to have a tool such as this as an option. Also check out http://social.technet.microsoft.com/wiki/contents/articles/7926.sharepoint-2010-tips-for-dealing-with-performance-issues-en-us.aspx it’s becoming a popular resource for checking tips about dealing performance issues. It’ll be updated if there’s any news on the 3rd party optimizer front.

The riddle of the five drop down lists with unique values

In a way, this post is a follow up of blog post https://sharepointdragons.com/2012/04/18/adding-jquery-to-a-visual-web-part-and-then-implement-parentchild-radio-buttons/. If you know your way around visual web parts or user controls, you don’t need to read it per se. If you don’t understand the contents of this post, it’s advisable to read it first.

Question: Suppose you have five drop down lists with an identical set of values (1-5 in this example), and suppose each selected value within this group of five lists needs to be unique. How do you implement that?

Answer: Well, a good way to that would be to use jQuery to handle the client-side validation, and implement a server-side version that kicks in if JavaScript is disabled or circumvented. The code below consists of a user control (.ascx) used in a visual web part and it’s code behind file.

Please note: The user control contains a CustomValidator control that doesn’t use the ControlToValidate property. This is because we’re not validating a specific control, instead we’re validating all list controls.This does mean that the Value property of the arguments parameter always contains an empty string.

Here’s the code for the user control (*.ascx):

<%@ Assembly Name=”$SharePoint.Project.AssemblyFullName$” %>
<%@ Assembly Name=”Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>
<%@ Register TagPrefix=”SharePoint” Namespace=”Microsoft.SharePoint.WebControls”
    Assembly=”Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>
<%@ Register TagPrefix=”Utilities” Namespace=”Microsoft.SharePoint.Utilities” Assembly=”Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>
<%@ Register TagPrefix=”asp” Namespace=”System.Web.UI” Assembly=”System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ %>
<%@ Import Namespace=”Microsoft.SharePoint” %>
<%@ Register TagPrefix=”WebPartPages” Namespace=”Microsoft.SharePoint.WebPartPages”
    Assembly=”Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>
<%@ Control Language=”C#” AutoEventWireup=”true” CodeBehind=”VisualWebPart1UserControl.ascx.cs”
    Inherits=”VisualWebPartProject1.VisualWebPart1.VisualWebPart1UserControl” %>
<asp:Label ID=”Label1″ runat=”server” Text=”Label”></asp:Label>
<SharePoint:ScriptLink ID=”ScriptLink1″ runat=”server” Name=”~sitecollection/SiteAssets/MyAssets/jquery-1.7.js” />

<script type=”text/javascript”>
    // Contains a list of priority values and the amount of occurrences.
    // E.g.: value 1 is selected 0 times, value 2 is selected 3 times.
    var _arrPrios;

    // Resets all priority values to zero occurrences.
    function Init() {
        // First is dummy entry, this makes it easier to understand the mapping between array index position and drop down list values.
        _arrPrios = [0, 0, 0, 0, 0, 0];
    }
   
    // Checks if all drop down lists contain a unique value.   
    function ValidateLists(src, args) {
        Init();
       
        // Select all priority drop down lists.
        $(“#divPrioLists select :selected”).each(function () {
            AddSelectedValue($(this).val());
        });
       
        // Skip first dummy entry (index = 0).       
        for (var i = 1; i < _arrPrios.length; i++) {
            if (_arrPrios[i] != 1) {               
                args.IsValid = false;
                return false;
            }
        }       

        args.IsValid = true;
    }

    // Count occurrences for every selected value (e.g. end user selected “1” 0 times, “2” 3 times.
    function AddSelectedValue(intValue) {
        _arrPrios[intValue] = ++_arrPrios[intValue];
    }
</script>

<asp:CustomValidator id=”CustomValidator2″ runat=”server” ErrorMessage = “All priority lists must have unique values”
ClientValidationFunction=”ValidateLists” OnServerValidate=”ValidateLists” >
</asp:CustomValidator>

<div id=”divPrioLists”>

<asp:DropDownList ID=”list1″ runat=”server”>
<asp:ListItem Text=”1″ Value=”1″ />
<asp:ListItem Text=”2″ Value=”2″ />
<asp:ListItem Text=”3″ Value=”3″ />
<asp:ListItem Text=”4″ Value=”4″ />
<asp:ListItem Text=”5″ Value=”5″ />
</asp:DropDownList>

<asp:DropDownList ID=”list2″ runat=”server”>
<asp:ListItem Text=”1″ Value=”1″ />
<asp:ListItem Text=”2″ Value=”2″ />
<asp:ListItem Text=”3″ Value=”3″ />
<asp:ListItem Text=”4″ Value=”4″ />
<asp:ListItem Text=”5″ Value=”5″ />
</asp:DropDownList>

<asp:DropDownList ID=”list3″ runat=”server”>
<asp:ListItem Text=”1″ Value=”1″ />
<asp:ListItem Text=”2″ Value=”2″ />
<asp:ListItem Text=”3″ Value=”3″ />
<asp:ListItem Text=”4″ Value=”4″ />
<asp:ListItem Text=”5″ Value=”5″ />
</asp:DropDownList>

<asp:DropDownList ID=”list4″ runat=”server”>
<asp:ListItem Text=”1″ Value=”1″ />
<asp:ListItem Text=”2″ Value=”2″ />
<asp:ListItem Text=”3″ Value=”3″ />
<asp:ListItem Text=”4″ Value=”4″ />
<asp:ListItem Text=”5″ Value=”5″ />
</asp:DropDownList>

<asp:DropDownList ID=”list5″ runat=”server”>
<asp:ListItem Text=”1″ Value=”1″ />
<asp:ListItem Text=”2″ Value=”2″ />
<asp:ListItem Text=”3″ Value=”3″ />
<asp:ListItem Text=”4″ Value=”4″ />
<asp:ListItem Text=”5″ Value=”5″ />
</asp:DropDownList>

</div>

<asp:Button ID=”btnSubmit”  runat=”server” Text=”Submit” />

Here’s the code for the code-behind file of the user control:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

namespace VisualWebPartProject1.VisualWebPart1
{
    public partial class VisualWebPart1UserControl : UserControl
    {

        protected override void OnInit(EventArgs e)
        {           
            // At this point, on a postback, the page hasn’t been validated yet.
            // You could call Page.Validate() explicitly or follow the normal flow of events.           
        }

        protected override void OnLoad(EventArgs e)
        {
            // At this point, on a postback, the page hasn’t been validated yet.
            // You could call Page.Validate() explicitly or follow the normal flow of events.           
        }

        protected override void OnPreRender(EventArgs e)
        {
            // The page has been validated on a postback.
            if (Page.IsPostBack && Page.IsValid)
            {

            }
        }

        // Contains a list of priority values and the amount of occurrences.
        // E.g.: value 1 is selected 0 times, value 2 is selected 3 times.
        private int[] _arrPrios = { 0, 0, 0, 0, 0, 0 };

        /// <summary>
        /// Server-side validation is equivalent to jQuery version, but kicks in in case end user disables JavaScript,
        /// or maliscuously tries to circumvent client-side validation.
        /// </summary>
        protected void ValidateLists(object source, ServerValidateEventArgs args)
        {
            // Register all selected values for all priority lists
            AddSelectedValue(list1, list2, list3, list4, list5);

            // Skip first dummy entry (index = 0).       
            for (int i = 1; i < _arrPrios.Length; i++)
            {
                if (_arrPrios[i] != 1)
                {
                    args.IsValid = false;
                    return;
                }
            }       

            args.IsValid = true;
        }

        /// <summary>
        /// Count occurrences for every selected value (e.g. end user selected “1” 0 times, “2” 3 times.
        /// </summary>       
        private void AddSelectedValue(params DropDownList[] args)
        {
            for (int i = 0; i < args.Length; i++)
            {
                var currentValue = Convert.ToInt32(args[i].SelectedValue);
                _arrPrios[currentValue] = ++_arrPrios[currentValue];
            }
        }
    }
}

Good link about SharePoint 2010 service accounts

When it’s time to plan your new SharePoint infrastructure, this article may come in handy: http://blog.falchionconsulting.com/index.php/2010/10/service-accounts-and-managed-service-accounts-in-sharepoint-2010/

Troubleshooting an SSRS report that times out

Just started a Wiki page that discusses what to do when you have a slow performing SSRS report. Everybody is more than welcome to contribute at http://social.technet.microsoft.com/wiki/contents/articles/9950.sharepoint-2010-best-practice-troubleshooting-an-ssrs-report-that-times-out.aspx

Convert SPMetal Linq query to CAML

As a follow up to article https://sharepointdragons.com/2012/04/21/how-to-check-if-the-current-user-has-already-created-a-list-item-of-a-certain-content-type/ , based on a reader’s question. This is a slightly updated version of the code that writes the underlying CAML to the console output window, like so:

astro.Log = Console.Out;

By explicitly calling it like so you’re exporting the CAML to a text file:

myconsole.exe > caml.txt

The complete code looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            // Open entities context generated by spmetal
            // if a sharepoint context is available, use new AstroDataContext(SPContext.Current.Web.Url) instead.
            using (var astro = new AstroDataContext(“http://astro”))
            {
                var timeItems = (from item in astro.MyMetalList
                                                                        where item.GetType() == typeof(Timecard)
                                                                        select (Timecard) item);

                // Call it like this: myconsole.exe > caml.txt
                astro.Log = Console.Out;               

                // Enter specific user name in lambda expression below, for example using: SPContext.Current.Web.CurrentUser.LoginName
                int occurrences = timeItems.Where(item => item.UserName.ToLower() == “loisandclark\\administrator”).Count();
                if (occurrences == 0)
                {
                    Console.WriteLine(“it’s ok to add a request”);
                }
                else if (occurrences == 1)
                {
                    Console.WriteLine(“a request has already been submitted”);
                }
                else
                {
                    Console.WriteLine(“There are duplicate requests. This is an error, contact the administrator”);
                }

                foreach (var item in timeItems)
                {
                    Console.WriteLine(item.Title);
                }
            }
        }
    }
}

 

The resulting CAML looks like this:

<View><Query><Where><BeginsWith><FieldRef Name=”ContentTypeId” /><Value Type=”ContentTypeId”>0x01</Value></BeginsWith></Where></Query><ViewFields><FieldRef Name=”ID” /><FieldRef Name=”owshiddenversion” /><FieldRef Name=”FileDirRef” /><FieldRef Name=”Title” /><FieldRef Name=”ContentTypeId” /><FieldRef Name=”CustomerName_x003a__x0020_Compan” /><FieldRef Name=”CustomerName_x003a__x0020_FirstN” /><FieldRef Name=”CustomerName_x003a__x0020_LastNa” /><FieldRef Name=”MyCustWF” /><FieldRef Name=”URL” /><FieldRef Name=”Comments” /><FieldRef Name=”URLwMenu” /><FieldRef Name=”URLNoMenu” /><FieldRef Name=”Date” /><FieldRef Name=”DayOfWeek” /><FieldRef Name=”Start” /><FieldRef Name=”End” /><FieldRef Name=”In” /><FieldRef Name=”Out” /><FieldRef Name=”Break” /><FieldRef Name=”ScheduledWork” /><FieldRef Name=”Overtime” /><FieldRef Name=”NightWork” /><FieldRef Name=”HolidayNightWork” /><FieldRef Name=”Late” /><FieldRef Name=”LeaveEarly” /><FieldRef Name=”Oof” /><FieldRef Name=”ShortComment” /><FieldRef Name=”Vacation” /><FieldRef Name=”NumberOfVacation” /><FieldRef Name=”UserName” /><FieldRef Name=”PercentComplete” /><FieldRef Name=”Body” /><FieldRef Name=”StartDate” /><FieldRef Name=”TaskDueDate” /><FieldRef Name=”Priority” /><FieldRef Name=”TaskStatus” /><FieldRef Name=”AssignedTo” /><FieldRef Name=”DueDate” /><FieldRef Name=”Status” /><FieldRef Name=”Predecessors” LookupId=”TRUE” /><FieldRef Name=”FileLeafRef” /><FieldRef Name=”ItemChildCount” /><FieldRef Name=”FolderChildCount” /><FieldRef Name=”DocumentSetDescription” /><FieldRef Name=”Modified_x0020_By” /><FieldRef Name=”Created_x0020_By” /><FieldRef Name=”WikiField” /><FieldRef Name=”_vti_RoutingExistingProperties” /><FieldRef Name=”PreviewOnForm” /><FieldRef Name=”FileType” /><FieldRef Name=”ImageSize” /><FieldRef Name=”ImageWidth” /><FieldRef Name=”ImageHeight” /><FieldRef Name=”ImageCreateDate” /><FieldRef Name=”SelectedFlag” /><FieldRef Name=”NameOrTitle” /><FieldRef Name=”RequiredField” /><FieldRef Name=”Keywords” /><FieldRef Name=”Thumbnail” /><FieldRef Name=”Preview” /><FieldRef Name=”AlternateThumbnailUrl” /><FieldRef Name=”Description” /><FieldRef Name=”MyBcsName_x003a__x0020_FirstName” /><FieldRef Name=”MyySingleLineOfText” /><FieldRef Name=”MyMultiLines” /><FieldRef Name=”MyNumber” /><FieldRef Name=”MyCurrency” /><FieldRef Name=”MyDatTime” /><FieldRef Name=”MyLookup_x003a__x0020_LastName” /><FieldRef Name=”MyLookup_x003a__x0020_Company” /><FieldRef Name=”MyLookup_x003a__x0020_Phone” /><FieldRef Name=”MyYesNo” /><FieldRef Name=”MyLinkOrPic” /><FieldRef Name=”MyCalc” /><FieldRef Name=”MyExtDaa_x003a__x0020_LastName” /><FieldRef Name=”MyExtDaa_x003a__x0020_Phone” /><FieldRef Name=”MyChoice” /><FieldRef Name=”MyPersonOrGroup” /><FieldRef Name=”MySText” /><FieldRef Name=”MyMText” /><FieldRef Name=”ReviewStatus” /><FieldRef Name=”MyPeople” /><FieldRef Name=”MyYesNo0″ /></ViewFields><RowLimit Paged=”TRUE”>2147483647</RowLimit></View>

How to check if the current user has already created a list item of a certain content type?

This probably would have been a bit of a hassle before SPMetal existed, right now it’s quite easy to do. Here’s what we didi:

  • We created a custom list.
  • In advanced settings, we’ve enabled content types and added the ootb content type TimeCard.
  • Then, we added two list items: one of the default type, and one of the TimeCard type.

Having our test list set up and ready to go, we’ve used SPMetal to create entities representing, among other, this custom list. We did this by issuing the following command at the command prompt (assuming 14/bin is in your environment path variables):

spmetal /web:http://astro /code Astro.cs

Add the generated Astro.cs file to a VS.NET SharePoint project (in this case, we’ve used a simple console application).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            // Open entities context generated by spmetal
            // if a sharepoint context is available, use new AstroDataContext(SPContext.Current.Web.Url) instead.
            using (var astro = new AstroDataContext(“http://astro”))
            {
                var timeItems = (from item in astro.MyMetalList
                                                                        where item.GetType() == typeof(Timecard)
                                                                        select (Timecard) item);

                // Enter specific user name in lambda expression below, for example using: SPContext.Current.Web.CurrentUser.LoginName
                int occurrences = timeItems.Where(item => item.UserName.ToLower() == “loisandclark\\administrator”).Count();
                if (occurrences == 0)
                {
                    Console.WriteLine(“it’s ok to add a request”);
                }
                else if (occurrences == 1)
                {
                    Console.WriteLine(“a request has already been submitted”);
                }
                else
                {
                    Console.WriteLine(“There are duplicate requests. This is an error, contact the administrator”);
                }

                foreach (var item in timeItems)
                {
                    Console.WriteLine(item.Title);
                }
            }
        }
    }
}

Authentication when using the SharePoint client object model

Normally, when you need to log in using a specific credential set in the SharePoint client object model, you’ll have to provide the correct credentials to authenticate to the SharePoint site collection, like so:

NetworkCredential credentials = new NetworkCredential(“username”, “pwd”, “domain”);

ClientContext context = new ClientContext(“http://thesitecollection”);

context.Credentials = credentials;

This won’t work if you have a claims based site set up supporting both Windows and forms authentication. See https://sharepointdragons.com/2012/01/30/claims-in-sharepoint-2010/ for more about setting that up. Instead, you need to set up the appropriate HTTP headers to disable Forms authentication, and it’ll work again:

ClientContext clientContext = new ClientContext(“http://thesitecollection“);clientContext.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(clientContext_ExecutingWebRequest);

Web site = clientContext.Web;

clientContext.Load(site);

clientContext.ExecuteQuery();

 

static void clientContext_ExecutingWebRequest(object sender, WebRequestEventArgs e){

    e.WebRequestExecutor.WebRequest.Headers.Add(“X-FORMS_BASED_AUTH_ACCEPTED”, “f”);

}

See http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/16cd0e26-8f3b-4ef2-bac4-c2c59849ab96 for more info.

How to set the people picker field to the current user?

An elegant way to do it is to use a bit of server side code with jQuery:

<script type=”text/javascript”> $(document).ready(function() {

$(‘div.ms-inputuserfield’).text($().SPServices.SPGetCurrentUser({fieldName: “Title”,debug: false}));

</script>

Looking for a sneaky way to prevent email notifications from being sent?

http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/4a42b080-3a59-45ae-a90e-2bce3d88657e provides the answer: just change the outgoing SMTP server to something else and switch it back 10-15 mins. Gotta love the simplicity of the idea.

So your mom threw away your Active Directory User…

What happens if a person leaves your organization and, as a consequence of that, somebody throws away the Active Directory user account, only to found out later that it still lingers on in SharePoint? You won’t be able to recreate the user because it’ll have a different SID, so what to do?

Use ol’ stsadm to the rescue: http://technet.microsoft.com/library/2a090c60-696f-4b68-8b6c-a19b763c60d3.aspx It allows you to migrate a user account to a new login name, optionally ignoring the SID meta data history.