<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Skavi</title>
	<atom:link href="http://www.skavi.be/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.skavi.be</link>
	<description>SharePoint consulting</description>
	<lastBuildDate>Mon, 14 Nov 2011 13:56:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>SharePoint folder performance</title>
		<link>http://www.skavi.be/sharepoint-folder-performance/</link>
		<comments>http://www.skavi.be/sharepoint-folder-performance/#comments</comments>
		<pubDate>Mon, 14 Nov 2011 13:53:38 +0000</pubDate>
		<dc:creator>Jeroen Van Bastelaere</dc:creator>
				<category><![CDATA[Folders]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.skavi.be/sharepoint-folder-performance/</guid>
		<description><![CDATA[In a recent project we had the idea to use folders as a starting position for queries to optimize the performance a bit further. To set a starting folder on an SPQuery object you need to set the Folder property to the SPFolder object you wish to search. This is what this post is about: [...]]]></description>
			<content:encoded><![CDATA[<p>In a recent project we had the idea to use folders as a starting position for queries to optimize the performance a bit further. To set a starting folder on an SPQuery object you need to set the Folder property to the SPFolder object you wish to search.</p>
<p>This is what this post is about: how to get that folder (by name) in C# in a performant matter.</p>
<p>Let’s get down to business: what I would like to do is write a function that takes in a folder name and it returns me the SPFolder object (in the first level, not recursively), for this I have several options:</p>
<ul>
<li>You can try SPList.Folders and loop over that</li>
<li>You can do SPList.RootFolder.SubFolders</li>
</ul>
<p>The first issue you might encounter with SPList.Folders is that it actually queries the whole list, meaning each and every item in that list <strong>recursively</strong>.</p>
<p>The code behind the Folders property is here:</p>
<pre class="brush: csharp; ">
public SPListItemCollection Folders
    {
      get
      {
        SPListItemCollection listItemCollection = (SPListItemCollection) null;
        if (!this.HasExternalDataSource)
          listItemCollection = this.GetItems(new SPQuery()
          {
            ViewAttributes = &quot;Scope=\&quot;&lt;strong&gt;RecursiveAll&lt;/strong&gt;\&quot;&quot;,
            Query = &quot;&lt;Where&gt;&lt;Eq&gt;&lt;FieldRef Name=\&quot;FSObjType\&quot; /&gt;&lt;Value Type=\&quot;Integer\&quot;&gt;1&lt;/Value&gt;&lt;/Eq&gt;&lt;/Where&gt;&quot;
          });
        return listItemCollection;
      }
    }
</pre>
<p>This means that if you have – by default – more than 5000 items you will have an SPQueryThrottledException which is something we like to avoid.</p>
<p>SPList.RootFolder.SubFolders obviously does not have this limitation, unless you have more than 5000 folders under your rootfolder.</p>
<p>The other implication of this recurveness is that querying SPList.Folders is considerably slower than going through SPList.RootFolder.SubFolders.</p>
<p>Here are some figures (I show the code at the end of this post):</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="bottom" width="355">
<p><b>Function</b></p>
</td>
<td valign="bottom" width="80">
<p><b>Time</b></p>
</td>
<td valign="bottom" width="80">&nbsp;</td>
</tr>
<tr>
<td valign="bottom" width="355">
<p>Folders.OfType&lt;SPListItem()&gt;()</p>
</td>
<td valign="bottom" width="80">
<p>2,513292</p>
</td>
<td valign="bottom" width="80">
<p>ms</p>
</td>
</tr>
<tr>
<td valign="bottom" width="355">
<p>Folders.Cast&lt;SPListItem&gt;()</p>
</td>
<td valign="bottom" width="80">
<p>0,124973</p>
</td>
<td valign="bottom" width="80">
<p>ms</p>
</td>
</tr>
<tr>
<td valign="bottom" width="355">
<p>RootFolder.SubFolders.OfType&lt;SPListItem()&gt;()</p>
</td>
<td valign="bottom" width="80">
<p>0,030432</p>
</td>
<td valign="bottom" width="80">
<p>ms</p>
</td>
</tr>
<tr>
<td valign="bottom" width="355">
<p>RootFolder.SubFolders.Cast&lt;SPListItem&gt;()</p>
</td>
<td valign="bottom" width="80">
<p>0,002376</p>
</td>
<td valign="bottom" width="80">
<p>ms</p>
</td>
</tr>
</tbody>
</table>
<p>&#160;</p>
<p>As you can see, going through RootFolder.SubFolders is way faster. On a sidenote: use Cast() instead of OfType() to be able to query it through Linq to Objects as it is one hell of a lot faster.</p>
<p>The code of the test:</p>
<pre class="brush: csharp;">public static SPListItem GetFolder1(SPList list, string folderName)
        {
            var results = from f in list.Folders.OfType&lt;SPListItem&gt;() where f.Title.Equals(folderName, StringComparison.InvariantCultureIgnoreCase) select f;
            if (results.Count() == 1)
                return results.ToList&lt;SPListItem&gt;()[0];

            return null;
        }

        public static SPListItem GetFolder2(SPList list, string folderName)
        {
            var results = from f in list.Folders.Cast&lt;SPListItem&gt;() where f.Title.Equals(folderName, StringComparison.InvariantCultureIgnoreCase) select f;
            if (results.Count() == 1)
                return results.ToList&lt;SPListItem&gt;()[0];

            return null;
        }

        public static SPListItem GetFolder3(SPList list, string folderName)
        {
            var results = from f in list.RootFolder.SubFolders.OfType&lt;SPFolder&gt;() where f.Name.Equals(folderName, StringComparison.InvariantCultureIgnoreCase) select f;
            if (results.Count() == 1)
                return results.ToList&lt;SPFolder&gt;()[0].Item;

            return null;
        }

        public static SPListItem GetFolder4(SPList list, string folderName)
        {
            var results = from f in list.RootFolder.SubFolders.Cast&lt;SPFolder&gt;() where f.Name.Equals(folderName, StringComparison.InvariantCultureIgnoreCase) select f;
            if (results.Count() == 1)
                return results.ToList&lt;SPFolder&gt;()[0].Item;

            return null;
        }</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.skavi.be/sharepoint-folder-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>List deleted / deleting event receivers not being hit when a site gets deleted</title>
		<link>http://www.skavi.be/list-deleted-deleting-event-receivers-not-being-hit-when-a-site-gets-deleted/</link>
		<comments>http://www.skavi.be/list-deleted-deleting-event-receivers-not-being-hit-when-a-site-gets-deleted/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 13:08:59 +0000</pubDate>
		<dc:creator>Jeroen Van Bastelaere</dc:creator>
				<category><![CDATA[Event receivers]]></category>
		<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.skavi.be/list-deleted-deleting-event-receivers-not-being-hit-when-a-site-gets-deleted/</guid>
		<description><![CDATA[This will be a very short blog with a finding we did today. If you have event receivers on your lists like: ListDeleting ListDeleted These don’t get hit when the parent site gets deleted, meaning you have to be very careful with it. If you really want to execute the logic that is contained within [...]]]></description>
			<content:encoded><![CDATA[<p>This will be a very short blog with a finding we did today. If you have event receivers on your lists like:</p>
<ul>
<li>ListDeleting</li>
<li>ListDeleted</li>
</ul>
<p>These don’t get hit when the parent site gets deleted, meaning you have to be very careful with it. If you really want to execute the logic that is contained within those events, you need to do it in the WebDeleted / WebDeleting events aswell.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skavi.be/list-deleted-deleting-event-receivers-not-being-hit-when-a-site-gets-deleted/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Preventing the use of webparts in specific sites</title>
		<link>http://www.skavi.be/preventing-the-use-of-webparts-in-specific-sites/</link>
		<comments>http://www.skavi.be/preventing-the-use-of-webparts-in-specific-sites/#comments</comments>
		<pubDate>Wed, 05 Oct 2011 20:22:18 +0000</pubDate>
		<dc:creator>Jeroen Van Bastelaere</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Styling]]></category>
		<category><![CDATA[Tricks]]></category>
		<category><![CDATA[Webpart]]></category>

		<guid isPermaLink="false">http://www.skavi.be/preventing-the-use-of-webparts-in-specific-sites/</guid>
		<description><![CDATA[For a recent project we had a business request to prevent the use of certain webparts in a specific site definition. Our initial investigation showed us that there is not that many information to be found on this subject so we decided it was time to share some information on the subject. There are a [...]]]></description>
			<content:encoded><![CDATA[<p>For a recent project we had a business request to prevent the use of certain webparts in a specific site definition.</p>
<p>Our initial investigation showed us that there is not that many information to be found on this subject so we decided it was time to share some information on the subject.</p>
<p>There are a few ways of implementing this, but each one of them has its advantages and drawbacks.</p>
<p>You can for example – in the case of custom webparts – implement custom logic to forcefully prevent the use of webparts in certain sites. This big disadvantages here are that you have to implement this additional logic to your webparts and this is obviously an overhead we can miss. You can not use this method for OOTB webparts either.</p>
<p>Another way would be to put item level security on the webpart files and just let trained users have access to it. This has obviously drawbacks that those privileges users can still add those webparts </p>
<p>We chose for a more modular approach by using CSS in combination with a delegate control. The advantage here is that it’s modular, but it can be overridden by a savvy power user.</p>
<table border="1" cellspacing="0" cellpadding="2" width="567">
<tbody>
<tr>
<td valign="top" width="131">&nbsp;</td>
<td valign="top" width="208"><strong>Advantages</strong></td>
<td valign="top" width="226"><strong>Disadvantages</strong></td>
</tr>
<tr>
<td valign="top" width="131"><strong>Custom logic</strong></td>
<td valign="top" width="208">
<ul>
<li>Bulletproof</li>
</ul>
</td>
<td valign="top" width="226">
<ul>
<li>Extra development</li>
<li>Overhead in code</li>
<li>Not usable for non-custom webparts</li>
</ul>
</td>
</tr>
<tr>
<td valign="top" width="131"><strong>Item level security</strong></td>
<td valign="top" width="208">
<ul>
<li>No code</li>
<li>Granular</li>
</ul>
</td>
<td valign="top" width="226">
<ul>
<li>Privileged users can still use it</li>
<li>Not clear that they’re “not supposed to”</li>
</ul>
</td>
</tr>
<tr>
<td valign="top" width="131"><strong>CSS + delegate control</strong></td>
<td valign="top" width="208">
<ul>
<li>No code</li>
<li>Able to enable or disable on a per site basis</li>
<li>Noone can see them if disabled</li>
</ul>
</td>
<td valign="top" width="226">
<ul>
<li>Can be overriden by a savvy power user</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>&#160;</p>
<p>In the sample below I will create a feature that will remove the “Content Rollup” category from the insert webpart ribbon:</p>
<p><a href="http://www.skavi.be/wp-content/uploads/2011/10/image.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" align="left" src="http://www.skavi.be/wp-content/uploads/2011/10/image_thumb.png" width="244" height="155" /></a></p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>To do this I created a new user control with the following CSS inside:</p>
<p>div.ms-wpadder-categories &gt; div[title=&quot;Content Rollup&quot;] {   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; display: none;    <br />}</p>
<p>Afterwards you need to create a new empty module and add the following to the elements.xml file:</p>
<p>&lt;Control Id=”AdditionalPageHead” Sequence=”50” ControlSrc=”~\_controltemplates\Your_project\Your_usercontrol.ascx” /&gt;</p>
<p>After this you add a new feature (web scoped) to the solution and add the newly created module to this feature.</p>
<p>When you deploy your solution and activate your feature the web parts with category “Content Rollup” will be hidden.</p>
<p><a href="http://www.skavi.be/wp-content/uploads/2011/10/image1.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.skavi.be/wp-content/uploads/2011/10/image_thumb1.png" width="244" height="19" /></a></p>
<p>&#160;</p>
<p>As you can see in the screenshot below, the “Content Rollup” category is hidden for end users.</p>
<p><a href="http://www.skavi.be/wp-content/uploads/2011/10/image2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.skavi.be/wp-content/uploads/2011/10/image_thumb2.png" width="244" height="182" /></a></p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>If you need to just hide specific webparts you can also use the following CSS:</p>
<p>div.ms-wpadder-items &gt; div[title*=&quot;Your_contains_statement&quot;] {   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; display: none;    <br />}</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skavi.be/preventing-the-use-of-webparts-in-specific-sites/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting random user profiles</title>
		<link>http://www.skavi.be/getting-random-user-profiles/</link>
		<comments>http://www.skavi.be/getting-random-user-profiles/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 20:33:45 +0000</pubDate>
		<dc:creator>Jeroen Van Bastelaere</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Search]]></category>
		<category><![CDATA[User Profiles]]></category>

		<guid isPermaLink="false">http://www.skavi.be/?p=22</guid>
		<description><![CDATA[Getting random user profiles is quite an easy task, but there is not much to be found on the internet about it except for some less than ideal solutions in my opinion. My ideal solution would be something that is scalable and takes into account the security of the User Profile Application. The solutions that [...]]]></description>
			<content:encoded><![CDATA[<p>Getting random user profiles is quite an easy task, but there is not much to be found on the internet about it except for some less than ideal solutions in my opinion.</p>
<p>My ideal solution would be something that is scalable and takes into account the security of the User Profile Application.</p>
<p>The solutions that I found all shared the same approach:</p>
<ul>
<li>Open the User Profile Application Service</li>
<li>Get the count of user profiles</li>
<li>Get X numbers between 0 and the number of user profiles</li>
<li>Get those user profiles</li>
</ul>
<p>I do have some issues with this which I would like to point out:</p>
<p>The count of the number of user profiles requires you to use an administrative account, which often works in a development environment (single machine, one account to rule them all kind of gig).. but when you deploy to a real live SharePoint farm you might encounter problems such as:</p>
<ul>
<li>The account used with the SPSecurity.RunWithElevatedPrivileges might not be administrator of the User Profile Application, thus giving you an access denied. This means going through even more unconfortable steps to get this working.</li>
<li>If you try to iterate over your User Profiles it goes quite slow (do not try to iterate over 10000+ userprofiles, you&#8217;ll be stuck for minutes)</li>
</ul>
<p>What my suggestion would be is to make use of the SharePoint search API and look for your user profiles there, the SharePoint search is very scalable and gets your results much faster than then the regular user profile API.</p>
<pre class="brush: csharp; ">
using (SPMonitoredScope scope = new SPMonitoredScope(&quot;Get random profiles&quot;))
{
StringBuilder Output = new StringBuilder();

FullTextSqlQuery q = new FullTextSqlQuery(SPContext.Current.Site);
q.QueryText = &quot;SELECT AccountName,FirstName,LastName,PictureURL,Path FROM Scope() WHERE \&quot;Scope\&quot;=&#039;People&#039; AND Contains(PictureURL, &#039;http&#039;)&quot;;
q.ResultTypes = ResultType.RelevantResults;
q.RowLimit = 10000;
ResultTableCollection results = q.Execute();
ResultTable queryResultsTable = results[ResultType.RelevantResults];

DataTable queryDataTable = new DataTable();
queryDataTable.Load(queryResultsTable, LoadOption.OverwriteChanges);

Random random = new Random();
int randomId = random.Next(queryDataTable.DefaultView.Count - 5);

DataTable dataTableToBind = new DataTable();
List&lt;string&gt; columns = new List&lt;string&gt;() { &quot;AccountName&quot;, &quot;FirstName&quot;, &quot;LastName&quot;, &quot;PictureURL&quot;, &quot;Path&quot; };
foreach (string column in columns)
dataTableToBind.Columns.Add(column);
for (int id = randomId; id &lt; randomId + 4; id++)
dataTableToBind.ImportRow(queryDataTable.Rows[id]);

rptUserProfiles.DataSource = dataTableToBind.DefaultView;
rptUserProfiles.DataBind();
}
</pre>
<p>The result can be as follows:</p>
<p><a href="http://www.skavi.be/wp-content/uploads/2011/09/image.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.skavi.be/wp-content/uploads/2011/09/image_thumb.png" alt="image" width="575" height="772" border="0" /></a></p>
<p>Note:</p>
<ul>
<li>In the above example one random ID is chosen and then it takes the next X random profiles to show, you can also take just X random profiles but then you would need to add some extra logic to it to avoid duplicates.</li>
<li>It is also recommended to cache the results you get back for performance reasons.</li>
<li>The above code is not production proof, it is a simple POC</li>
</ul>
<p>Just a closing note: if you try to iterate the user profiles through the user profile API you will quickly be stuck for seconds or even minutes, so it is highly recommended not to try this approach.</p>
<p>The method of using the search API is highly underused in my opinion and should be used as much as possible for the iteration over items that are spread across the farm, including &#8211; but not limited to &#8211; the search of user profiles.</p>
<p>Special thanks to Stéphane Eyskens (<a title="http://www.silver-it.com/" href="http://www.silver-it.com/">http://www.silver-it.com/</a>)!</p>
<p>Sourcecode: <a href="http://www.skavi.be/wp-content/uploads/2011/09/Skavi.UserProfiles.zip">http://www.skavi.be/wp-content/uploads/2011/09/Skavi.UserProfiles.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.skavi.be/getting-random-user-profiles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Skavi BVBA is opgericht</title>
		<link>http://www.skavi.be/skavi-bvba-is-opgericht/</link>
		<comments>http://www.skavi.be/skavi-bvba-is-opgericht/#comments</comments>
		<pubDate>Tue, 23 Aug 2011 08:53:52 +0000</pubDate>
		<dc:creator>Jeroen Van Bastelaere</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.skavi.be/?p=5</guid>
		<description><![CDATA[On the first of september I will start my new challenge as an independant consultant, working under the brand Skavi BVBA. My specialities in the field of SharePoint are: Coaching Consulting Development Analysis Training Have a nice day!]]></description>
			<content:encoded><![CDATA[<p>On the first of september I will start my new challenge as an independant consultant, working under the brand Skavi BVBA.</p>
<p>My specialities in the field of SharePoint are:</p>
<ul>
<li>Coaching</li>
<li>Consulting</li>
<li>Development</li>
<li>Analysis</li>
<li>Training</li>
</ul>
<p>Have a nice day!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skavi.be/skavi-bvba-is-opgericht/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

