<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0ACSX48cSp7ImA9WhVUF0w.&quot;"><id>tag:blogger.com,1999:blog-11096258</id><updated>2012-05-22T21:42:48.079+02:00</updated><category term="JBOWS" /><category term="BCS" /><category term="Encoding" /><category term="Customization" /><category term="Schema" /><category term="ILM" /><category term="UserProfile" /><category term="BRE" /><category term="ASP.NET" /><category term="ASC2011" /><category term="WF" /><category term="TDD" /><category term="Taxonomy" /><category term="MySite" /><category term="RoboCopy" /><category term="Other" /><category term="EDA" /><category term="SqlServer" /><category term="Flex" /><category term="IAM" /><category term="WinForms" /><category term="ActiveDirectory" /><category term="jQuery" /><category term="Publishing" /><category term="VisualStudio" /><category term="UX" /><category term="MVP" /><category term="WS-Trust" /><category term="ServiceApplications" /><category term="Design" /><category term="ADFS" /><category term="BAM" /><category term="Kerberos" /><category term="IIS" /><category term="SCSF" /><category term="TableAdapter" /><category term="Versioning" /><category term="TermStore" /><category term="IA" /><category term="Topology" /><category term="WebPart" /><category term="XPath" /><category term="ContentType" /><category term="ManagedMetadataService" /><category term="SiteStructure" /><category term="Faults" /><category term="Office1x" /><category term="S+S" /><category term="InfoPath" /><category term="Serializing" /><category term="Innovation" /><category term="Claims" /><category term="MVC" /><category term="WIF" /><category term="Binding" /><category term="Messaging" /><category term="Exchange" /><category term="ECDM" /><category term="ESB" /><category term="CAB" /><category term="AJAX" /><category term="SOA-G" /><category term="Build" /><category term="WOA" /><category term="Integration" /><category term="ES-EWA" /><category term="SOA" /><category term="BTS" /><category term="Programming" /><category term="Configuration" /><category term="VSTO" /><category term="WSDL" /><category term="SaaS" /><category term="WSSF" /><category term="STS" /><category term="CIM" /><category term="ActivityFeed" /><category term="DDD" /><category term="Virtualization" /><category term="SecureStoreService" /><category term="EntLib" /><category term="Findability" /><category term="Governance" /><category term="ASMX" /><category term="REST" /><category term="MDM" /><category term="WS*OA" /><category term="SharePoint" /><category term="WS-Security" /><category term="Modeling" /><category term="BPM" /><category term="Web2.0" /><category term="CEP" /><category term="Contracts" /><category term="Search" /><category term="FAST" /><category term="SDO" /><category term="MSCRM" /><category term="WS-Federation" /><category term="SearchDriven" /><category term="Transactions" /><category term="ADO.NET" /><category term="ContentTypeHub" /><category term="UAG" /><category term="WCF" /><category term="InformationManagement" /><category term="Validation" /><category term="VAB" /><category term="Patterns" /><category term="Enterprise2.0" /><title>InfoWorker Solutions</title><subtitle type="html">When in doubt, hesitate!</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://kjellsj.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>259</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/InfoworkerSolutions" /><feedburner:info uri="infoworkersolutions" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DU8BSXYzeip7ImA9WhVUEUo.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-3865320230748988153</id><published>2012-05-07T09:45:00.000+02:00</published><updated>2012-05-16T16:17:38.882+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-16T16:17:38.882+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Search" /><category scheme="http://www.blogger.com/atom/ns#" term="XPath" /><category scheme="http://www.blogger.com/atom/ns#" term="WebPart" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="SearchDriven" /><title>Exploring Search Results Step-by-Step in SharePoint 2010</title><content type="html">Using search to provide a news archive in SharePoint 2010 is a wellknown solution. Just add the core results web-part to a page and configure it to query for your news article content type and sort it in descending order. Then customize the result XSLT to tune the content and layout of the news excerpts to look like a new archive. Add also the search box, the search refiners and the results paging web-parts and you have a functional news archive in no time.&lt;br /&gt;
&lt;br /&gt;
This post is about providing contextual navigation&amp;nbsp;by adding "&amp;lt;&amp;lt; previous", "next &amp;gt;&amp;gt;" and "result" links to the article pages,&amp;nbsp;to allow users to explore the&amp;nbsp;result set&amp;nbsp;in a step-by-step manner. Norwegians will reckognize this way of exploring results from&amp;nbsp;&lt;a href="http://finn.no/"&gt;finn.no&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-3pxVmthgekc/T6aBUhk8jII/AAAAAAAAAZs/uGGwAZflcKc/s1600/result_set_navigator.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="96" src="http://2.bp.blogspot.com/-3pxVmthgekc/T6aBUhk8jII/AAAAAAAAAZs/uGGwAZflcKc/s320/result_set_navigator.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
For a user or visitor to be able to navigate the results, the result set must be cached per user. The search results are in XML format, and it contains a sequential id and the URL for each hit. This allows the navigation control to use XPath to locate the current result by id, and get the URLs for the previous and next results. The user query must also be cached so that clicking the "result" link will show the expected search results.&lt;br /&gt;
&lt;br /&gt;
Override the&amp;nbsp;CoreResultsWebPart&amp;nbsp;as shown in my &lt;a href="http://kjellsj.blogspot.com/2012/04/elevated-search-results-sharepoint-2010.html"&gt;Getting Elevated Search Results in SharePoint 2010&lt;/a&gt;&amp;nbsp;post to add per-user caching of the search results. If your site allows for anonymous visitors, you need to decide on how to keep tab on them. In the code I've used the requestor IP address, which is not 100% foolproof, but this allows me to avoid using cookies for now.&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Presentation&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    [ToolboxItemAttribute(&lt;span class="kwrd"&gt;false&lt;/span&gt;)]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; NewsArchiveCoreResultsWebPart : CoreResultsWebPart&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ScopeNewsArticles&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            = &lt;span class="str"&gt;"Scope=\"News Archive\""&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CacheKeyResultsXmlDocument&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;            &lt;/span&gt;= &lt;span class="str"&gt;"Puzzlepart_CoreResults_XmlDocument_User:"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CacheKeyUserQueryString&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;            &lt;/span&gt;= &lt;span class="str"&gt;"Puzzlepart_CoreResults_UserQuery_User:"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _cacheUserQueryTimeMinutes = 720;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _cacheUserResultsTimeMinutes = 30;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;base&lt;/span&gt;.CreateChildControls();&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;var&lt;/span&gt; error = SharePointUtilities.CreateErrorLabel(ex);&lt;/pre&gt;
&lt;pre&gt;                Controls.Add(error);&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; XPathNavigator GetXPathNavigator(&lt;span class="kwrd"&gt;string&lt;/span&gt; viewPath)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;//return base.GetXPathNavigator(viewPath);&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            SetCachedUserQuery();&lt;/pre&gt;
&lt;pre class="alt"&gt;            XmlDocument xmlDocument = GetXmlDocumentResults();&lt;/pre&gt;
&lt;pre&gt;            SetCachedResults(xmlDocument);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            XPathNavigator xPathNavigator = xmlDocument.CreateNavigator();&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; xPathNavigator;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; XmlDocument GetXmlDocumentResults()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            XmlDocument xmlDocument = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            QueryManager queryManager =&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;            &lt;/span&gt;SharedQueryManager.GetInstance(Page, QueryNumber).QueryManager;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            Location location = queryManager[0][0];&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; query = location.SupplementaryQueries;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (query.IndexOf(ScopeNewsArticles,&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                &lt;/span&gt;StringComparison.CurrentCultureIgnoreCase) &amp;lt; 0)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; userQuery =&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                    &lt;/span&gt;queryManager.UserQuery + &lt;span class="str"&gt;" "&lt;/span&gt; + ScopeNewsArticles;&lt;/pre&gt;
&lt;pre&gt;                queryManager.UserQuery = userQuery.Trim();&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            xmlDocument = queryManager.GetResults(queryManager[0]);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; xmlDocument;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetCachedUserQuery()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; qs = HttpUtility.ParseQueryString&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                    &lt;/span&gt;(Page.Request.QueryString.ToString());&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (qs[&lt;span class="str"&gt;"resultid"&lt;/span&gt;] != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                qs.Remove(&lt;span class="str"&gt;"resultid"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;            HttpRuntime.Cache.Insert(UserQueryCacheKey(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Page),&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;               &lt;/span&gt;qs.ToString(), &lt;span class="kwrd"&gt;null&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;               &lt;/span&gt;Cache.NoAbsoluteExpiration,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;&lt;span style="background-color: transparent;"&gt;               &lt;/span&gt;new&lt;/span&gt; TimeSpan(0, 0, _cacheUserQueryTimeMinutes, 0));&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetCachedResults(XmlDocument xmlDocument)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            HttpRuntime.Cache.Insert(ResultsCacheKey(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Page),&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;               &lt;/span&gt;xmlDocument, &lt;span class="kwrd"&gt;null&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;               &lt;/span&gt;Cache.NoAbsoluteExpiration,&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&lt;span style="background-color: transparent;"&gt;               &lt;/span&gt;new&lt;/span&gt; TimeSpan(0, 0, _cacheUserResultsTimeMinutes, 0));&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; UserQueryCacheKey(Page page)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; visitorId = GetVisitorId(page);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; queryCacheKey = String.Format(&lt;span class="str"&gt;"{0}{1}"&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                &lt;/span&gt;CacheKeyUserQueryString, visitorId);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; queryCacheKey;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ResultsCacheKey(Page page)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; visitorId = GetVisitorId(page);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; resultsCacheKey = String.Format(&lt;span class="str"&gt;"{0}{1}"&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;                &lt;/span&gt;CacheKeyResultsXmlDocument, visitorId);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; resultsCacheKey;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetCachedUserQuery(Page page)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; userQuery =&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;                &lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;)HttpRuntime.Cache[UserQueryCacheKey(page)];&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; userQuery;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; XmlDocument GetCachedResults(Page page)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            XmlDocument results =&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;                &lt;/span&gt;(XmlDocument)HttpRuntime.Cache[ResultsCacheKey(page)];&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; results;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetVisitorId(Page page)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;//TODO: use cookie for anonymous visitors&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; id = page.Request.ServerVariables[&lt;span class="str"&gt;"HTTP_X_FORWARDED_FOR"&lt;/span&gt;]&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                &lt;/span&gt;?? page.Request.ServerVariables[&lt;span class="str"&gt;"REMOTE_ADDR"&lt;/span&gt;];&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt;(SPContext.Current.Web.CurrentUser != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                id = SPContext.Current.Web.CurrentUser.LoginName;&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; id;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
I've used sliding expiration on the cache to allow for the user to spend some time exploring the results. The result set is cached for a short time by default, as this can be quite large. The user query text is, however, small and cached for a long time, allowing the users to at least get their results back after a period of inactivity.&lt;br /&gt;
&lt;br /&gt;
As suggested by &lt;a href="http://techmikael.blogspot.com/"&gt;Mikael Svenson&lt;/a&gt;, an alternative to caching would be running the query again using the static QueryManager page object to get the result set. This would require using another result key element than the dynamic &amp;lt;id&amp;gt; number to ensure that the current result lookup is not scewed by new results being returned by the search. An example would be using a content type field such as "NewsArticlePermaId" if it exists.&lt;br /&gt;
&lt;br /&gt;
Overriding the&amp;nbsp;&lt;span style="background-color: #f4f4f4; font-family: Consolas, 'Courier New', Courier, monospace; font-size: x-small; line-height: 18px;"&gt;GetXPathNavigator&lt;/span&gt;&amp;nbsp;method gets you the cached results that the navigation control needs. In addition, the navigator code needs to know which is the result set id of the current page. This is done by customizing the result XSLT and adding a "resultid" parameter to the $siteUrl variable for each hit.&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;. . . &lt;/pre&gt;
&lt;pre&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;xsl:template&lt;/span&gt; &lt;span class="attr"&gt;match&lt;/span&gt;&lt;span class="kwrd"&gt;="Result"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;xsl:variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="id"&lt;/span&gt; &lt;span class="attr"&gt;select&lt;/span&gt;&lt;span class="kwrd"&gt;="id"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;xsl:variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="currentId"&lt;/span&gt; &lt;span class="attr"&gt;select&lt;/span&gt;&lt;span class="kwrd"&gt;="concat($IdPrefix,$id)"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;xsl:variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="url"&lt;/span&gt; &lt;span class="attr"&gt;select&lt;/span&gt;&lt;span class="kwrd"&gt;="url"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;xsl:variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="resultid"&lt;/span&gt; &lt;span class="attr"&gt;select&lt;/span&gt;&lt;span class="kwrd"&gt;="concat('?resultid=', $id)"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;xsl:variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="siteUrl"&lt;/span&gt; &lt;span class="attr"&gt;select&lt;/span&gt;&lt;span class="kwrd"&gt;="concat($url, $resultid)"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;. . . &lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The result set navigation control is quite simple, looking up the current result by id and getting the URLs for the previous and next results (if any) and adding the "resultid" to keep the navigation logic going forever.&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Presentation&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; NewsArchiveResultsNavigator : Control&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; NewsArchivePageUrl { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _resultId = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; XmlDocument _results = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.CreateChildControls();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            _resultId = Page.Request.QueryString[&lt;span class="str"&gt;"resultid"&lt;/span&gt;];&lt;/pre&gt;
&lt;pre class="alt"&gt;            _results = NewsArchiveCoreResultsWebPart.GetCachedResults(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Page);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt;(_results == &lt;span class="kwrd"&gt;null&lt;/span&gt; || _resultId == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="rem"&gt;//render nothing&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            AddResultsNavigationLinks();&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddResultsNavigationLinks()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; prevUrl = GetPreviousResultPageUrl();&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; linkPrev = &lt;span class="kwrd"&gt;new&lt;/span&gt; HyperLink()&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                Text = &lt;span class="str"&gt;"&amp;lt;&amp;lt; Previous"&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;                NavigateUrl = prevUrl&lt;/pre&gt;
&lt;pre class="alt"&gt;            };&lt;/pre&gt;
&lt;pre&gt;            linkPrev.Enabled = (prevUrl.Length &amp;gt; 0);&lt;/pre&gt;
&lt;pre class="alt"&gt;            Controls.Add(linkPrev);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; resultsUrl = GetSearchResultsPageUrl();&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; linkResults = &lt;span class="kwrd"&gt;new&lt;/span&gt; HyperLink()&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                Text = &lt;span class="str"&gt;"Result"&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class="alt"&gt;                NavigateUrl = resultsUrl&lt;/pre&gt;
&lt;pre&gt;            };&lt;/pre&gt;
&lt;pre class="alt"&gt;            Controls.Add(linkResults);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; nextUrl = GetNextResultPageUrl();&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; linkNext = &lt;span class="kwrd"&gt;new&lt;/span&gt; HyperLink()&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                Text = &lt;span class="str"&gt;"Next &amp;gt;&amp;gt;"&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class="alt"&gt;                NavigateUrl = nextUrl&lt;/pre&gt;
&lt;pre&gt;            };&lt;/pre&gt;
&lt;pre class="alt"&gt;            linkNext.Enabled = (nextUrl.Length &amp;gt; 0);&lt;/pre&gt;
&lt;pre&gt;            Controls.Add(linkNext);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetPreviousResultPageUrl()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetSpecificResultUrl(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetNextResultPageUrl()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetSpecificResultUrl(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetSpecificResultUrl(&lt;span class="kwrd"&gt;bool&lt;/span&gt; useNextResult)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; url = &lt;span class="str"&gt;""&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_results != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; xpath =&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                    &lt;/span&gt;String.Format(&lt;span class="str"&gt;"/All_Results/Result[id='{0}']"&lt;/span&gt;, _resultId);&lt;/pre&gt;
&lt;pre&gt;                XPathNavigator xNavigator = _results.CreateNavigator();&lt;/pre&gt;
&lt;pre class="alt"&gt;                XPathNavigator xCurrentNode = xNavigator.SelectSingleNode(xpath);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (xCurrentNode != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;                {&lt;/pre&gt;
&lt;pre&gt;                    &lt;span class="kwrd"&gt;bool&lt;/span&gt; hasNode = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (useNextResult)&lt;/pre&gt;
&lt;pre&gt;                        hasNode = xCurrentNode.MoveToNext();&lt;/pre&gt;
&lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                        hasNode = xCurrentNode.MoveToPrevious();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (hasNode &amp;amp;&amp;amp;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;                        &lt;/span&gt;xCurrentNode.LocalName.Equals(&lt;span class="str"&gt;"Result"&lt;/span&gt;))&lt;/pre&gt;
&lt;pre class="alt"&gt;                    {&lt;/pre&gt;
&lt;pre&gt;                        &lt;span class="kwrd"&gt;string&lt;/span&gt; resultId =&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;                        &lt;/span&gt;xCurrentNode.SelectSingleNode(&lt;span class="str"&gt;"id"&lt;/span&gt;).Value;&lt;/pre&gt;
&lt;pre class="alt"&gt;                        &lt;span class="kwrd"&gt;string&lt;/span&gt; fileUrl =&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                        &lt;/span&gt;xCurrentNode.SelectSingleNode(&lt;span class="str"&gt;"url"&lt;/span&gt;).Value;&lt;/pre&gt;
&lt;pre&gt;                        url = String.Format(&lt;span class="str"&gt;"{0}?resultid={1}"&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;                           &lt;/span&gt;fileUrl, resultId);&lt;/pre&gt;
&lt;pre class="alt"&gt;                    }&lt;/pre&gt;
&lt;pre&gt;                }&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; url;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetSearchResultsPageUrl()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; url = NewsArchivePageUrl;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; userQuery =&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;                &lt;/span&gt;NewsArchiveCoreResultsWebPart.GetCachedUserQuery(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Page);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(userQuery))&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                url = String.Format(&lt;span class="str"&gt;"{0}?resultid={1}"&lt;/span&gt;, url, _resultId);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                url = String.Format(&lt;span class="str"&gt;"{0}?{1}&amp;amp;resultid={2}"&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;                    &lt;/span&gt;url, userQuery, _resultId);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; url;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Note how I use the "resultid" URL parameter to discern between normal navigation to a page and result set navigation between pages. If the resultid parameter is not there, then the navigation controls are hidden. The same goes for when there are no cached results. The "result" link could always be visible for as long as the user's query text is cached.&lt;br /&gt;
&lt;br /&gt;
You can also provide this result set exploration capability for all kinds of pages, not just for a specific page layout, by adding the result set navigation control to your master page(s). The result set &amp;lt;id&amp;gt; and &amp;lt;url&amp;gt; elements are there for all kind of pages stored in your SharePoint solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-3865320230748988153?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/WEFwre2bB40" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/3865320230748988153/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=3865320230748988153" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3865320230748988153?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3865320230748988153?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/WEFwre2bB40/explore-search-results-step-sharepoint.html" title="Exploring Search Results Step-by-Step in SharePoint 2010" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-3pxVmthgekc/T6aBUhk8jII/AAAAAAAAAZs/uGGwAZflcKc/s72-c/result_set_navigator.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/05/explore-search-results-step-sharepoint.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4GQ3oyfyp7ImA9WhVWF0Q.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-3966533722371128417</id><published>2012-04-30T10:11:00.003+02:00</published><updated>2012-04-30T16:42:02.497+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-30T16:42:02.497+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Search" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration" /><category scheme="http://www.blogger.com/atom/ns#" term="SearchDriven" /><title>Almost Excluding Specific Search Results in SharePoint 2010</title><content type="html">Sometimes you want to hide certain content from being exposed through search in certain SharePoint web-applications, even if the user really has access to the information in the actual content source. A scenario is intranet search that is openly used, but in which you want to prevent accidental information exposure. Think of a group working together on reqruiting, where the HR manager use the search center looking for information - you wouldn't want even excerpts of confidential information to be exposed in the search results.&lt;br /&gt;
&lt;br /&gt;
So you carefully plan your content sources and crawl rules to only index the least possible amount of information. Still, even with crawl rules you will often need to tweak the query scope rules to exclude content at a more fine-grained level, or even add new scopes for providing search-driven content to users. Such configuration typically involves using exclude rules on content types or content sources. This is a story of how SharePoint can throw you a search results curveball, leading to accidental information disclosure.&lt;br /&gt;
&lt;br /&gt;
In this scenario, I had created a new content source &lt;b&gt;JobVault&lt;/b&gt; for crawling the HR site-collection in another SharePoint web-application, to be exposed only through a custom shared scope. So I tweaked the rules of the existing scopes such as "All Sites" to exclude the Puzzlepart JobVault content source, and added a new &lt;b&gt;JobReqruiting&lt;/b&gt;&amp;nbsp;scope that required the JobVault content source and included the content type &lt;b&gt;JobHired&lt;/b&gt; and excluded the content type &lt;b&gt;JobFired&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
So no shared scopes defined in the Search Service Application (SSA) included JobFired information, as all scopes either excluded the HR content source or excluded the confidential content type.&amp;nbsp;To my surprise our SharePoint search center would find and expose such pages and documents when searching for "you're fired!!!".&lt;br /&gt;
&lt;br /&gt;
Knowing that the search center by default uses the "All Sites" scope when no specific scope is configured or defined in the keyword query, it was back to the SSA to verify the scope. It was all in order, and doing a property search on &lt;b&gt;Scope:"All Sites"&lt;/b&gt; got me the expected results with no confidential data in it. The same result for &lt;b&gt;Scope:"JobReqruiting"&lt;/b&gt;, no information exposure there either. It looked very much like a best bet, but there where no best bet keywords defined for the site-collection.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-FvGlHAiNBWY/T55JKcLVKjI/AAAAAAAAAZU/opl1L_tJ1OM/s1600/SP2010_top_federated_results_web_part.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="182" src="http://3.bp.blogspot.com/-FvGlHAiNBWY/T55JKcLVKjI/AAAAAAAAAZU/opl1L_tJ1OM/s400/SP2010_top_federated_results_web_part.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The search center culprit was the Top Federated Results web-part in our basic search site, by default showing results from the local search index very much like best bets. That was the same location as defined in the core results web-part, so why this difference?&lt;br /&gt;
&lt;br /&gt;
Looking into the details of the "Local Search Results" federated location, the reason became clear: "This location provides unscoped results from the Local Search index". The keyword here is "unscoped".&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-X9_b1FyV7Bg/T55CJ35kWsI/AAAAAAAAAY8/hUL5hF1sqxE/s1600/SP2010_LocalSearchIndex_FederatedLocation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://1.bp.blogspot.com/-X9_b1FyV7Bg/T55CJ35kWsI/AAAAAAAAAY8/hUL5hF1sqxE/s400/SP2010_LocalSearchIndex_FederatedLocation.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The solution is to add the "All Sites" scope to the federated location to ensure that results that you want to hide are also excluded from the federated results web-part. Add it to the "Query Template" and optionally also to the "More Results Link Template" under the "Location Information" section in "Edit Federated Location".&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-jWtWTmeJScM/T55E2ElVx6I/AAAAAAAAAZI/1fEZieBUp9I/s1600/SP2010_LocalSearchIndex_FederatedLocation_AllSites_Scope.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://2.bp.blogspot.com/-jWtWTmeJScM/T55E2ElVx6I/AAAAAAAAAZI/1fEZieBUp9I/s400/SP2010_LocalSearchIndex_FederatedLocation_AllSites_Scope.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Now the content is hidden when searching. Not through query security trimming, but through query filtering. Forgetting to add the filter somewhere can expose the information, but then only to users that have permission to see the content anyway. The results are still security trimmed, so this no actual information disclosure risk.&lt;br /&gt;
&lt;br /&gt;
Note that this approach is no replacement for real information security; if that is what you need, don't crawl confidential information from an SSA that is exposed through openly available SharePoint search, even on your intranet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-3966533722371128417?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/jcVFMrVcffU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/3966533722371128417/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=3966533722371128417" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3966533722371128417?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3966533722371128417?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/jcVFMrVcffU/hiding-search-results-sharepoint-2010.html" title="Almost Excluding Specific Search Results in SharePoint 2010" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-FvGlHAiNBWY/T55JKcLVKjI/AAAAAAAAAZU/opl1L_tJ1OM/s72-c/SP2010_top_federated_results_web_part.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/04/hiding-search-results-sharepoint-2010.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08ERHo-cSp7ImA9WhVWEUs.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-7966226923377724900</id><published>2012-04-21T12:36:00.001+02:00</published><updated>2012-04-23T09:23:25.459+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-23T09:23:25.459+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration" /><category scheme="http://www.blogger.com/atom/ns#" term="TermStore" /><category scheme="http://www.blogger.com/atom/ns#" term="ContentTypeHub" /><category scheme="http://www.blogger.com/atom/ns#" term="ManagedMetadataService" /><title>Migrate SharePoint 2010 Term Sets between MMS Term Stores</title><content type="html">When using the SharePoint 2010 &lt;a href="http://www.sharepointconfig.com/2011/09/adding-managed-metadata-fields-to-sharepoint-publishing-pages/"&gt;managed metadata fields connected to termsets&lt;/a&gt; stored in the Managed Metadata Service (MMS) term store in your solutions, you should have a designated master MMS that is reused across all your SharePoint environment such as the &lt;a href="http://www.slideshare.net/kjellsj/sharepoint-2010-farm-architecture-design-infrastructure"&gt;development, test, staging and production farms&lt;/a&gt;. Having a single master termstore across all farms gives you the same termsets and terms with the same identifiers all over, allowing you to move content and content types from staging to production &lt;a href="http://www.cleverworkarounds.com/2011/01/09/sp2010-migrating-managed-metadata-term-sets-to-another-farm-on-another-domain/"&gt;without invalidating all the fields and data connected to the MMS term store&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
You'll find a lot of termset tools on CodePlex, some that use the standard SharePoint 2010 CSV import file format (which is without identifiers), and some that on paper does what you need, but don't fully work. Some of the better tools are &lt;a href="http://metadataexportsps.codeplex.com/"&gt;SolidQ Managed Metadata Exporter&lt;/a&gt;&amp;nbsp;for export and import of termset (CSV-style), &lt;a href="http://sptermstoreutilities.codeplex.com/"&gt;SharePoint Term Store Powershell Utilities&lt;/a&gt; for fixing orphaned terms, and finally&amp;nbsp;&lt;a href="http://taxonomyandtermstore.codeplex.com/"&gt;SharePoint Taxonomy and TermStore Utilities&lt;/a&gt; for real migration.&lt;br /&gt;
&lt;br /&gt;
There are, however, standard SP2010 PowerShell cmdlets that allow you to migrate the complete termstore with full fidelity between Managed Metadata Service applications across farms. The drawback is that you can't do selective migration of specific termsets, the whole term store will be overwritten by the migration.&lt;br /&gt;
&lt;br /&gt;
This script exports the term store to a backup file:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;# MMS Application ID has to be passed &lt;span class="kwrd"&gt;for&lt;/span&gt; -Identity parameter&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;/pre&gt;
&lt;pre&gt;Export-SPMetadataWebServicePartitionData -Identity &lt;span class="str"&gt;"12810c05-1f06-4e35-a6c3-01fc485956a3"&lt;/span&gt; -ServiceProxy -ServiceProxy &lt;span class="str"&gt;"Managed Metadata Service"&lt;/span&gt; -Path &lt;span class="str"&gt;"\\Puzzlepart\termstore\pzl-staging.bak"&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
This script imports the backup by overwriting the term store:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;# MMS Application ID has to be passed &lt;span class="kwrd"&gt;for&lt;/span&gt; -Identity parameter&lt;/pre&gt;
&lt;pre&gt;# NOTE: overwrites all existing termsets &lt;span class="kwrd"&gt;from&lt;/span&gt; MMS&lt;/pre&gt;
&lt;pre class="alt"&gt;# NOTE: overwrites the MMS content type HUB URL - must be reconfigured on target MMS proxy after restoring&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;/pre&gt;
&lt;pre&gt;Import-SPMetadataWebServicePartitionData -Identity &lt;span class="str"&gt;"53150c05-1f06-4e35-a6c3-01fc485956a3"&lt;/span&gt; -ServiceProxy &lt;span class="str"&gt;"Managed Metadata Service"&lt;/span&gt; -path &lt;span class="str"&gt;"\\Puzzlepart\termstore\pzl-staging.bak"&lt;/span&gt; -OverwriteExisting&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Tajeshwar Singh has posted several posts on using these scripts, including how to solve typical issues:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/b/taj/archive/2011/01/11/site-collection-backup-restore-and-managed-metadata.aspx"&gt;Site Collection Backup\Restore and Managed Metadata&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/b/taj/archive/2010/10/20/import-spmetadatawebservicepartitiondata-and-bulk-load-problem.aspx"&gt;Import-SPMetadataWebServicePartitionData and BULK LOAD Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/b/taj/archive/2011/03/20/import-spmetadatawebservicepartitiondata-error-in-multi-server-deployment.aspx"&gt;Import-SPMetadataWebServicePartitionData error in multi server deployment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
Note that after the term store migration, the MMS &lt;a href="http://kjellsj.blogspot.com/2011/05/provisioning-sites-content-type-hub.html"&gt;content type HUB&lt;/a&gt; URL configuration will also have been overwritten. You may not notice for some time, but the content type HUB publishing and subscriber timer jobs will stop working. What you will notice, is that if you try to click republish on a content type in the HUB, you'll get an "No valid proxy can be found to do this operation" error. See&amp;nbsp;&lt;a href="http://www.sharepointanalysthq.com/2010/11/how-to-change-the-content-type-hub-url/"&gt;How to change the Content Type Hub URL&lt;/a&gt; by Michal Pisarek for the steps to rectify this.&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;Set-SPMetadataServiceApplication -Identity &lt;span class="str"&gt;"Managed Metadata Service"&lt;/span&gt; -HubURI &lt;span class="str"&gt;"http://puzzlepart:8181/"&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
After resetting this MMS configuration, you should verify that the &lt;a href="http://www.sptechweb.com/content/article.aspx?ArticleID=36166"&gt;content type publishing works correctly&lt;/a&gt;&amp;nbsp;by republishing and running the timer jobs. Use "Site Collection Administration &amp;gt; Content Type Publishing" as shown on page 2 in Chris Geier's article to verify that the correct HUB is set and that HUB content types are pushed to the subscribers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-7966226923377724900?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/-sTobm5gh8Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/7966226923377724900/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=7966226923377724900" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7966226923377724900?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7966226923377724900?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/-sTobm5gh8Q/sharepoint-mms-migrate-termset.html" title="Migrate SharePoint 2010 Term Sets between MMS Term Stores" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/04/sharepoint-mms-migrate-termset.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYMSXwyfCp7ImA9WhVUEks.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-3696596896879577410</id><published>2012-04-16T11:19:00.004+02:00</published><updated>2012-05-17T17:06:28.294+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-17T17:06:28.294+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Search" /><category scheme="http://www.blogger.com/atom/ns#" term="WebPart" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="SecureStoreService" /><category scheme="http://www.blogger.com/atom/ns#" term="SearchDriven" /><category scheme="http://www.blogger.com/atom/ns#" term="ServiceApplications" /><title>Getting Elevated Search Results in SharePoint 2010</title><content type="html">I often use the SharePoint 2010 search CoreResultsWebPart in combination with scopes, content types and managed properties defined in the Search Service Application (SSA) for having dynamic search-driven content in pages. Sometimes the users might need to see some excerpt of content that they really do not have access to, and that you don't want to grant them access to either; e.g. to show a summary to anonymous visitors on your public web-site from selected content that is really stored in the extranet web-application in the SharePoint farm.&lt;br /&gt;
&lt;br /&gt;
What is needed then is to execute the search query with elevated privileges using a custom core results web-part. As my colleague Mikael Svenson shows in&amp;nbsp;&lt;a href="http://techmikael.blogspot.com/2010/12/doing-blended-search-results-in.html"&gt;Doing blended search results in SharePoint–Part 2: The Custom CoreResultsWebPart Way&lt;/a&gt;, it is quite easy to get at the search results code and use the SharedQueryManager object that actually runs the query. Create a web-part that inherits the ootb web-part and override the&amp;nbsp;GetXPathNavigator method like this:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Presentation&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    [ToolboxItemAttribute(&lt;span class="kwrd"&gt;false&lt;/span&gt;)]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; JobPostingCoreResultsWebPart : CoreResultsWebPart&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.CreateChildControls();&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; XPathNavigator GetXPathNavigator(&lt;span class="kwrd"&gt;string&lt;/span&gt; viewPath)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            XmlDocument xmlDocument = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            QueryManager queryManager =&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;              SharedQueryManager.GetInstance(Page, QueryNumber)&lt;/pre&gt;
&lt;pre&gt;                .QueryManager;&lt;/pre&gt;
&lt;pre class="alt"&gt;            SPSecurity.RunWithElevatedPrivileges(&lt;span class="kwrd"&gt;delegate&lt;/span&gt;()&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                xmlDocument = queryManager.GetResults(queryManager[0]);&lt;/pre&gt;
&lt;pre&gt;            });&lt;/pre&gt;
&lt;pre class="alt"&gt;            XPathNavigator xPathNavigator = xmlDocument.CreateNavigator();&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; xPathNavigator;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;a href="http://www.threewill.com/2010/06/connect-to-sharepoint-forwarding-user-identities/"&gt;Running the query with elevated privileges&lt;/a&gt; means that it can return any content that the app-pool identity has access to. Thus, it is important that you grant that account read permissions only on content that you would want just any user to see. Remember that the security trimming is done at query time, not at crawl time, with standard SP2010 server search. It is the &lt;a href="http://msdn.microsoft.com/en-us/magazine/ff796226.aspx"&gt;credentials passed to the location's SSA proxy&lt;/a&gt; that is used for the security trimming. Use WindowsIdentity.GetCurrent() from the System.Security.Principal namespace if you need to get at the app-pool account from your code.&lt;br /&gt;
&lt;br /&gt;
You would want to add a scope and/or some fixed keywords to the query in the code before getting the results, in order to prevent malicious or accidental misuse of the elevated web-part to search for just anything in the crawled content of the associated SSA that the app-pool identity has access to. Another alternative is to run the query under another identity than the app-pool account by using real Windows impersonation in combination with the Secure Store Service (see &lt;a href="http://kjellsj.blogspot.com/2010/10/secure-store-service-create-site.html"&gt;this post&lt;/a&gt; for all the needed code) as this allows for using a specific content query account.&lt;br /&gt;
&lt;br /&gt;
The nice thing about using the built-in query manager this way, rather than &lt;a href="http://social.technet.microsoft.com/Forums/lv-LV/sharepoint2010programming/thread/8e0dfda7-4348-4514-8177-0d8a46db0644"&gt;running your own KeywordQuery and providing your own result XML&lt;/a&gt; local to the custom web-part instance, is that the shared QueryManager's Location object will get its Result XML document populated. This is important for the correct behavior for the other search web-parts on the page using the same QueryNumber / UserQuery, such as the paging and refiners web-parts.&lt;br /&gt;
&lt;br /&gt;
The result XmlDocument will also be in the correct format with lower case column names, correct hit highlighting data, correct date formatting, duplicate trimming, getting &amp;lt;path&amp;gt; to be &amp;lt;url&amp;gt; and &amp;lt;urlEncoded&amp;gt;, have the correct additional managed and crawled properties in the result such as &amp;lt;FileExtension&amp;gt; and &amp;lt;ows_MetadataFacetInfo&amp;gt;, etc, in addition to having the row &amp;lt;id&amp;gt; element and &amp;lt;imageUrl&amp;gt; added to each result. If you override by using a replacement KeywordQuery you must also implement code to apply appended query, fixed query, scope, result properties, sorting and paging yourself to gain full fidelity for your custom query web-part configuration.&lt;br /&gt;
&lt;br /&gt;
The &lt;a href="http://msdn.microsoft.com/en-us/library/ms584121(v=office.12).aspx"&gt;formatting and layout of the search results is as usual controlled by overriding the result XSLT&lt;/a&gt;. This includes the data such as any links in the results, as you don't want the users to click on links that just will give them access denied errors.&lt;br /&gt;
&lt;br /&gt;
When using the search box web-part, use the contextual scope option for the scopes dropdown with care. The ContextualScopeUrl (u=) parameter will default to the current web-application, causing an empty result set&amp;nbsp;when using the custom core results web-part against a content source from&amp;nbsp;another SharePoint web-application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-3696596896879577410?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/noZvGu4AugM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/3696596896879577410/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=3696596896879577410" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3696596896879577410?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3696596896879577410?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/noZvGu4AugM/elevated-search-results-sharepoint-2010.html" title="Getting Elevated Search Results in SharePoint 2010" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/04/elevated-search-results-sharepoint-2010.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ECQnk5fCp7ImA9WhVXFko.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-6085627974625546467</id><published>2012-03-08T09:21:00.000+01:00</published><updated>2012-04-17T16:07:43.724+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-17T16:07:43.724+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Publishing" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><title>SharePoint 'Approve on behalf of' for Publishing Pages</title><content type="html">Using &lt;a href="http://blogs.msdn.com/b/sanjaynarang/archive/2009/02/19/relationships-between-moderation-approval-status-scheduling-versions-and-workflows.aspx"&gt;require approval and the approval workflow&lt;/a&gt; in SharePoint 2010 publishing, or just approval on the pages library in the &lt;a href="http://keutmann.blogspot.com/2008/05/publishingfeaturehandler-feature-id.html"&gt;simple publishing&lt;/a&gt; configuration, is straight forwards when using the browser as you're only logged in as one person with a limited set of roles and thus set of rights. Typically a page author can edit a page and submit it for approval, but not actually approve the page to be published on the site. When you need to approve, you have to log on as a user with approval rights.&lt;br /&gt;
&lt;br /&gt;
Sometimes you need to extend the user experience to allow an author to make simple changes to an already published page, such as extending the publishing end date, and republish it directly without having to do all the approval procedures all over again.&amp;nbsp;So you create a custom "extend expiry date" ribbon button, elevate the privileges from code and call the Page ListItem File Approve method, only to get an access denied error.&lt;br /&gt;
&lt;br /&gt;
In SharePoint 2010, it is not sufficient to be the app-pool identity (SHAREPOINT\System) or even a site-collection admin, you have to run the approval procedures as a user with approval privileges. So your code needs to impersonate a user in the "Approvers" group to be able to approve an item on behalf of the current user.&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ApproveOnBehalfOfUser(&lt;/pre&gt;
&lt;pre class="alt"&gt;SPListItem item, &lt;span class="kwrd"&gt;string&lt;/span&gt; approversGroupName, &lt;span class="kwrd"&gt;string&lt;/span&gt; userName, &lt;span class="kwrd"&gt;string&lt;/span&gt; comment)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    Guid siteId = item.ParentList.ParentWeb.Site.ID;&lt;/pre&gt;
&lt;pre&gt;    Guid webId = item.ParentList.ParentWeb.ID;&lt;/pre&gt;
&lt;pre class="alt"&gt;    Guid listId = item.ParentList.ID;&lt;/pre&gt;
&lt;pre&gt;    Guid itemId = item.UniqueId;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    SPUserToken approveUser = GetApproverUserToken(siteId, webId, approversGroupName);&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (approveUser == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(String.Format(&lt;/pre&gt;
&lt;pre&gt;&lt;span class="str"&gt;"The group '{0}' has no members of type user, cannot approve item on behalf of '{1}'"&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;approversGroupName, userName));&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SPSite site = &lt;span class="kwrd"&gt;new&lt;/span&gt; SPSite(siteId, approveUser))&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (SPWeb web = site.OpenWeb(webId))&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; approveItem = web.Lists[listId].Items[itemId];&lt;/pre&gt;
&lt;pre class="alt"&gt;            approveItem.File.Approve(comment);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; SPUserToken GetApproverUserToken(&lt;/pre&gt;
&lt;pre&gt;Guid siteId, Guid webId, &lt;span class="kwrd"&gt;string&lt;/span&gt; approversGroupName)&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    SPUserToken token = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;    SPSecurity.RunWithElevatedPrivileges(() =&amp;gt;&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (SPSite site = &lt;span class="kwrd"&gt;new&lt;/span&gt; SPSite(siteId))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;using&lt;/span&gt; (SPWeb web = site.OpenWeb(webId))&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;var&lt;/span&gt; group = web.SiteGroups[approversGroupName];&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (group != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;                {&lt;/pre&gt;
&lt;pre&gt;                    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (SPUser user &lt;span class="kwrd"&gt;in&lt;/span&gt; group.Users)&lt;/pre&gt;
&lt;pre class="alt"&gt;                    {&lt;/pre&gt;
&lt;pre&gt;                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!user.IsDomainGroup &amp;amp;&amp;amp; !user.IsSiteAdmin)&lt;/pre&gt;
&lt;pre class="alt"&gt;                        {&lt;/pre&gt;
&lt;pre&gt;                            token = web.GetUserToken(user.LoginName);&lt;/pre&gt;
&lt;pre class="alt"&gt;                            &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;                        }&lt;/pre&gt;
&lt;pre class="alt"&gt;                    }&lt;/pre&gt;
&lt;pre&gt;                }&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    });&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; token;&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The code picks a user from the approvers group, and then impersonates that user using a SPUserToken object. From within the impersonated user token scope, the given page list item is opened again with the permissions of an approver, and finally the page is approved on behalf of the given page author.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-6085627974625546467?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/lPMpwb0p51I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/6085627974625546467/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=6085627974625546467" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/6085627974625546467?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/6085627974625546467?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/lPMpwb0p51I/sharepoint-approve-on-behalf-of-access.html" title="SharePoint 'Approve on behalf of' for Publishing Pages" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/03/sharepoint-approve-on-behalf-of-access.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcFR3wzeip7ImA9WhVVFUU.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-2325606130380548633</id><published>2012-02-28T09:27:00.003+01:00</published><updated>2012-05-09T19:03:36.282+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-09T19:03:36.282+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ActiveDirectory" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="ADFS" /><title>SharePoint ResolvePrincipal for ADFS users</title><content type="html">Granting permissions in SharePoint 2010 by code is done by &lt;a href="http://kjellsj.blogspot.com/2008/10/sharepoint-acls-roledefinitions.html"&gt;assigning roles to user or group principals&lt;/a&gt;, or for claims-based application, to a claim type instance. As you will find out when implementing a claims-based applications against ADFS, the&amp;nbsp;SPUtility &lt;a href="http://msdn.microsoft.com/en-us/library/ms458648.aspx"&gt;ResolvePrincipal&lt;/a&gt; method that you can use against the Windows identity provider and also against forms-based authentication (FBA), don't work for ADFS users. That is no surprise when looking at the SPPrincipalSource enum that lists the site's user info list, the Windows provider, and then the FBA membership and role providers.&lt;br /&gt;
&lt;br /&gt;
The solution is rather simple, pass the user identity claim value such as the user's e-mail address used in ADFS to the SPClaimProviderManager &lt;a href="http://msdn.microsoft.com/en-us/library/ee560863.aspx"&gt;CreateUserClaim&lt;/a&gt; method using the TrustedProvider issuer type. Then pass the generated claim to EnsureUser to get a SPPrincipal wrapping the user identity claim:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; SPUser ResolveAdfsPrincipal(SPWeb web, &lt;span class="kwrd"&gt;string&lt;/span&gt; email, &lt;span class="kwrd"&gt;string&lt;/span&gt; issuerIdentifier)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    SPUser user = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!SPClaimProviderManager.IsEncodedClaim(email))&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        SPClaim claim = SPClaimProviderManager.CreateUserClaim(email, SPOriginalIssuerType.TrustedProvider, issuerIdentifier);&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (claim != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; userClaim = claim.ToEncodedString();&lt;/pre&gt;
&lt;pre&gt;            user = web.EnsureUser(userClaim);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; user;&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; SPUser ResolvePrincipal(SPWeb web, &lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    SPUser user = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;    SPPrincipalInfo identity = SPUtility.ResolvePrincipal(web, email, SPPrincipalType.All, SPPrincipalSource.All, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (identity != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        user = web.EnsureUser(identity.LoginName);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; user;&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Use the name of your ADFS identity provider as the issuer identifer parameter. If you're unsure of what this string should be, add a user to a SharePoint group using the UI and look at the identity claim value generated by SharePoint.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-ycgk9-nmH44/T0yOcgtm-UI/AAAAAAAAAYI/S_ipgDLDodc/s1600/SP2010_identity_user_claim_adfs2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="80" src="http://4.bp.blogspot.com/-ycgk9-nmH44/T0yOcgtm-UI/AAAAAAAAAYI/S_ipgDLDodc/s400/SP2010_identity_user_claim_adfs2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The identity claim value follows a specific format, and with ADFS (trusted provider) the issuer identifier name is always the 2nd pipe-separated value. The 1st part starting "i:" is for "identity" type claim, while the ending ".t" is for "trusted" provider (".f" is FBA, ".w" is Windows). In between is an encoding of the &lt;a href="http://technet.microsoft.com/en-us/library/ee913589(v=ws.10).aspx"&gt;claim type&lt;/a&gt; used as the &lt;a href="http://technet.microsoft.com/en-us/library/ff607753.aspx"&gt;IdentifierClaim&lt;/a&gt; specified when registering the ADFS trusted identity provider. See the &lt;a href="http://blogs.msdn.com/b/scicoria/archive/2011/06/30/identity-claims-encoding-for-sharepoint.aspx"&gt;full list of claim type and claim value type encoding characters here&lt;/a&gt;. The 3rd part of the claim is the actual user claim value. This was an oversimplified explanation, refer to the&amp;nbsp;&lt;a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=27569"&gt;SP2010 claims whitepaper&lt;/a&gt; for complete details.&lt;br /&gt;
&lt;br /&gt;
Side note: The &lt;a href="http://www.wictorwilen.se/Post/How-Claims-encoding-works-in-SharePoint-2010.aspx"&gt;claim type encoding logic&lt;/a&gt; is important when using a custom claims provider (CCP) to augment the claimset with your own custom claim types. If you have CCPs on multiple SharePoint farms, it’s very important that you &lt;a href="http://msdn.microsoft.com/en-us/magazine/hh547099.aspx"&gt;deploy all the CCPs in the same sequence across farms&lt;/a&gt; to ensure that the claim type mapping and encoding character for a custom claim type becomes the same across all farms. The best approach for ensuring parity across farms might be &lt;a href="http://www.theidentityguy.com/articles/2010/10/19/adding-claims-to-an-existing-token-issuer-in-sharepoint-2010.html"&gt;using Powershell to add the claim mappings&lt;/a&gt;&amp;nbsp;first.&lt;br /&gt;
&lt;br /&gt;
The code really doesn't resolve the user against ADFS, it just creates a claim type instance that authorization later on can validate against the logged in user's token (claim set). If the user's token contains the correct value for the claim type assigned to the securable object, then the user is authorized according to the role assignment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-2325606130380548633?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/x5AT5isM-Rc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/2325606130380548633/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=2325606130380548633" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/2325606130380548633?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/2325606130380548633?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/x5AT5isM-Rc/sharepoint-resolveprincipal-for-adfs.html" title="SharePoint ResolvePrincipal for ADFS users" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-ycgk9-nmH44/T0yOcgtm-UI/AAAAAAAAAYI/S_ipgDLDodc/s72-c/SP2010_identity_user_claim_adfs2.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/02/sharepoint-resolveprincipal-for-adfs.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEAHQn4_eCp7ImA9WhRaFEo.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-4253331518439761757</id><published>2012-02-16T18:59:00.000+01:00</published><updated>2012-02-17T10:58:53.040+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-17T10:58:53.040+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Search" /><category scheme="http://www.blogger.com/atom/ns#" term="Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="ContentType" /><category scheme="http://www.blogger.com/atom/ns#" term="WebPart" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="FAST" /><category scheme="http://www.blogger.com/atom/ns#" term="SearchDriven" /><title>Reusable SPGridView with Multiple Filter and Sort Columns</title><content type="html">The venerable SPGridView still has its use in SharePoint 2010 when your data is not stored in a list or accessible as an external content type through BCS. A typical example is when using a KeywordQuery to build a search-driven web-part feeding on results as DataTable as show in &lt;a href="http://www.dotnetmafia.com/blogs/dotnettipoftheday/archive/2010/08/12/how-to-use-the-sharepoint-2010-enterprise-search-keywordquery-class.aspx"&gt;How to: Use the SharePoint 2010 Enterprise Search KeywordQuery Class&lt;/a&gt;&amp;nbsp;by Corey Roth. Another example is cross-site queries using &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsitedataquery.aspx"&gt;SPSiteDataQuery&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-b_qmUkFDTwY/Tz1WgLhq0VI/AAAAAAAAAX8/H7o3yJLViC4/s1600/SPGridViewSortFilter.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-b_qmUkFDTwY/Tz1WgLhq0VI/AAAAAAAAAX8/H7o3yJLViC4/s1600/SPGridViewSortFilter.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
The SPGridView can use a DataTable as its data source, but several things from sorting arrows to filtering don't work as expected when not using an ObjectDataSource. As Shawn Kirby shows in&amp;nbsp;&lt;a href="http://sharethefrustration.blogspot.com/2010/02/spgridview-webpart-with-multiple-filter.html"&gt;SPGridView WebPart with Multiple Filter and Sort Columns&lt;/a&gt; it is quite easy to implement support for such features.&lt;br /&gt;
&lt;br /&gt;
In this post, I show how to generalize Shawn's web-part code into a SPGridView derived class and a data source class wrapping a DataTable, isolating this functionality from the web-part code itself, for both better reusability and separation of concerns.&lt;br /&gt;
&lt;br /&gt;
First the simple abstract data source class that you must implement to populate your data set:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Core&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SPGridViewDataSource&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; DataTable SelectData(&lt;span class="kwrd"&gt;string&lt;/span&gt; sortExpression);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Sort(DataTable dataSource, &lt;span class="kwrd"&gt;string&lt;/span&gt; sortExpression)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//clean up the sort expression if needed - the sort descending &lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;//menu item causes the double in some cases &lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (sortExpression.ToLowerInvariant().EndsWith(&lt;span class="str"&gt;"desc desc"&lt;/span&gt;))&lt;/pre&gt;
&lt;pre&gt;                sortExpression = sortExpression.Substring(0, sortExpression.Length - 5);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;//need to handle the actual sorting of the data&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(sortExpression))&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                DataView view = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataView(dataSource);&lt;/pre&gt;
&lt;pre&gt;                view.Sort = sortExpression;&lt;/pre&gt;
&lt;pre class="alt"&gt;                DataTable newTable = view.ToTable();&lt;/pre&gt;
&lt;pre&gt;                dataSource.Clear();&lt;/pre&gt;
&lt;pre class="alt"&gt;                dataSource.Merge(newTable);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The&amp;nbsp;SPGridViewDataSource class provides the SelectData method that you must override, and a completed Sort method that allows the SPGridView to sort your DataTable. Note that this class must be stateless as required by any class used as an ObjectDataSource. Its logic cannot be combined with the grid view class, as it will get instantiated new every time the ObjectDataSource calls SelectData.&lt;br /&gt;
&lt;br /&gt;
Then the derived grid view with support for filtering and sorting, including the arrows and filter images:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Core&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SPGridViewMultiSortFilter : SPGridView&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; SPGridViewMultiSortFilter()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.FilteredDataSourcePropertyName = &lt;span class="str"&gt;"FilterExpression"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.FilteredDataSourcePropertyFormat = &lt;span class="str"&gt;"{1} = '{0}'"&lt;/span&gt;;            &lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; ObjectDataSource _gridDS;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] _sortingSeparator = { &lt;span class="str"&gt;','&lt;/span&gt; };&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] _filterSeparator = { &lt;span class="str"&gt;"AND"&lt;/span&gt; };&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; ObjectDataSource GridDataSource&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;get&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; _gridDS; }&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;private set&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                _gridDS = value;&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.DataSourceID = _gridDS.ID;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; AllowMultiSorting { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; AllowMultiFiltering { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; FilterExpression&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;. . .&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; SortExpression&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;. . .&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.CreateChildControls();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Sorting += &lt;span class="kwrd"&gt;new&lt;/span&gt; GridViewSortEventHandler(GridView_Sorting);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.RowDataBound += &lt;span class="kwrd"&gt;new&lt;/span&gt; GridViewRowEventHandler(GridView_RowDataBound);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; GridView_Sorting(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, GridViewSortEventArgs e)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            EnsureChildControls();&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; direction = e.SortDirection.ToString();&lt;/pre&gt;
&lt;pre&gt;            direction = (direction == &lt;span class="str"&gt;"Descending"&lt;/span&gt;) ? &lt;span class="str"&gt;" DESC"&lt;/span&gt; : &lt;span class="str"&gt;""&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            SortExpression = e.SortExpression + direction;&lt;/pre&gt;
&lt;pre class="alt"&gt;            e.SortExpression = SortExpression;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//keep the object dataset filter&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(FilterExpression))&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                _gridDS.FilterExpression = FilterExpression;&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; GridView_RowDataBound(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, GridViewRowEventArgs e)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            EnsureChildControls();&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (sender == &lt;span class="kwrd"&gt;null&lt;/span&gt; || e.Row.RowType != DataControlRowType.Header)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            BuildFilterView(_gridDS.FilterExpression);&lt;/pre&gt;
&lt;pre class="alt"&gt;            SPGridView grid = sender &lt;span class="kwrd"&gt;as&lt;/span&gt; SPGridView;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;// Show icon on filtered and sorted columns &lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; grid.Columns.Count; i++)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;. . .&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; BuildFilterView(&lt;span class="kwrd"&gt;string&lt;/span&gt; filterExp)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;. . .&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;//update the filter&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(lastExp))&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                FilterExpression = lastExp;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;//reset object dataset filter&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(FilterExpression))&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                _gridDS.FilterExpression = FilterExpression;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; ObjectDataSource SetObjectDataSource(&lt;span class="kwrd"&gt;string&lt;/span&gt; dataSourceId, SPGridViewDataSource dataSource)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            ObjectDataSource gridDS = &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjectDataSource();&lt;/pre&gt;
&lt;pre&gt;            gridDS.ID = dataSourceId;&lt;/pre&gt;
&lt;pre class="alt"&gt;            gridDS.SelectMethod = &lt;span class="str"&gt;"SelectData"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            gridDS.TypeName = dataSource.GetType().AssemblyQualifiedName;&lt;/pre&gt;
&lt;pre class="alt"&gt;            gridDS.EnableViewState = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            gridDS.SortParameterName = &lt;span class="str"&gt;"SortExpression"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;            gridDS.FilterExpression = FilterExpression;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.GridDataSource = gridDS;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; gridDS;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Only parts of the SPGridViewMultiSortFilter code is shown here, see download link below for the complete code. Note that I have added two properties that controls whether multi-column sorting and multi-column filtering are allowed or not.&lt;br /&gt;
&lt;br /&gt;
This is an excerpt from a web-part that shows search results using the grid:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Presentation&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    [ToolboxItemAttribute(&lt;span class="kwrd"&gt;false&lt;/span&gt;)]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; JobPostingRollupWebPart : WebPart&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; SPGridViewMultiSortFilter GridView = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                CreateJobPostingGrid();&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                Label error = &lt;span class="kwrd"&gt;new&lt;/span&gt; Label();&lt;/pre&gt;
&lt;pre class="alt"&gt;                error.Text = String.Format(&lt;span class="str"&gt;"An unexpected error occurred: {0}"&lt;/span&gt;, ex.Message);&lt;/pre&gt;
&lt;pre&gt;                error.ToolTip = ex.StackTrace;&lt;/pre&gt;
&lt;pre class="alt"&gt;                Controls.Add(error);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateJobPostingGrid()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            GridView = &lt;span class="kwrd"&gt;new&lt;/span&gt; SPGridViewMultiSortFilter();&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;  . . .&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            GridView.AllowSorting = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            GridView.AllowMultiSorting = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;            GridView.AllowFiltering = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            GridView.FilterDataFields = &lt;span class="str"&gt;"Title,Author,Write,"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;  . . .&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            Panel panel = &lt;span class="kwrd"&gt;new&lt;/span&gt; Panel();&lt;/pre&gt;
&lt;pre class="alt"&gt;            panel.Controls.Add(GridView);&lt;/pre&gt;
&lt;pre&gt;            Controls.Add(panel);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            PopulateGridDataSource();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;//must bind in OnPreRender&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//GridView.DataBind();  &lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnPreRender(EventArgs e)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            GridView.DataBind();&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PopulateGridDataSource()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; dataSource = &lt;span class="kwrd"&gt;new&lt;/span&gt; ApprovedJobPostingDataSource();&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; gridDS = GridView.SetObjectDataSource(&lt;span class="str"&gt;"gridDS"&lt;/span&gt;, dataSource);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//add the data source&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            Controls.Add(gridDS);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Note how the data source is created and assigned to the grid view, but also added to the control set of the web-part itself. This is required for the grid's DataSourceId binding to find the ObjectDataSource at run-time. Also note that data binding cannot be triggered from CreateChildControls as it is too early in the control's life cycle. The DataBind method must be called from OnPreRender to allow for view state and child controls to load before the sorting and filtering postback events&lt;br /&gt;
&lt;br /&gt;
Finally, this is an example of how to implement a search-driven&amp;nbsp;SPGridViewDataSource:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Presentation&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ApprovedJobPostingDataSource : SPGridViewDataSource&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _cacheKey = &lt;span class="str"&gt;"Puzzlepart_Godkjente_Jobbannonser"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; DataTable SelectData(&lt;span class="kwrd"&gt;string&lt;/span&gt; sortExpression)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            DataTable dataTable = (DataTable)HttpRuntime.Cache[_cacheKey];&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (dataTable == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                dataTable = GetJobPostingData();&lt;/pre&gt;
&lt;pre class="alt"&gt;                HttpRuntime.Cache.Insert(_cacheKey, dataTable, &lt;span class="kwrd"&gt;null&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Sort(dataTable, sortExpression);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; dataTable;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; DataTable GetJobPostingData()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            DataTable results = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataTable();&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; jobPostingManager = &lt;span class="str"&gt;"Puzzlepart Jobbannonse arbeidsleder"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; jobPostingAssistant = &lt;span class="str"&gt;"Puzzlepart Jobbannonse assistent"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; approvedStatus = &lt;span class="str"&gt;"0"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            SPSite site = SPContext.Current.Site;&lt;/pre&gt;
&lt;pre class="alt"&gt;            KeywordQuery query = &lt;span class="kwrd"&gt;new&lt;/span&gt; KeywordQuery(site);&lt;/pre&gt;
&lt;pre&gt;            query.QueryText = String.Format(&lt;/pre&gt;
&lt;pre&gt;&lt;span class="str"&gt;"ContentType:\"{0}\" ContentType:\"{1}\" ModerationStatus:\"{2}\""&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;jobPostingManager, jobPostingAssistant, approvedStatus);&lt;/pre&gt;
&lt;pre class="alt"&gt;            query.ResultsProvider = SearchProvider.Default;&lt;/pre&gt;
&lt;pre&gt;            query.ResultTypes = ResultType.RelevantResults;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            ResultTableCollection resultTables = query.Execute();&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (resultTables.Count &amp;gt; 0)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                ResultTable searchResults = resultTables[ResultType.RelevantResults];&lt;/pre&gt;
&lt;pre&gt;                results.Load(searchResults, LoadOption.OverwriteChanges);&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; results;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
That was not too hard, was it? Note that SearchProvider Default work for both FAST (FS4SP) and a standard SharePoint 2010 Search Service Application (SSA).&lt;br /&gt;
&lt;br /&gt;
All the code can be downloaded from &lt;a href="https://skydrive.live.com/redir.aspx?cid=4cbe2e9714073667&amp;amp;resid=4CBE2E9714073667!439&amp;amp;parid=root"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-4253331518439761757?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/r8qqQKSx_Zw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/4253331518439761757/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=4253331518439761757" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/4253331518439761757?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/4253331518439761757?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/r8qqQKSx_Zw/spgridview-multiple-filter-sort-columns.html" title="Reusable SPGridView with Multiple Filter and Sort Columns" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-b_qmUkFDTwY/Tz1WgLhq0VI/AAAAAAAAAX8/H7o3yJLViC4/s72-c/SPGridViewSortFilter.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/02/spgridview-multiple-filter-sort-columns.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YHRXY7fSp7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-3117460831809973350</id><published>2012-01-19T18:34:00.000+01:00</published><updated>2012-02-16T20:38:54.805+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-16T20:38:54.805+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WIF" /><category scheme="http://www.blogger.com/atom/ns#" term="STS" /><category scheme="http://www.blogger.com/atom/ns#" term="WS-Trust" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration" /><category scheme="http://www.blogger.com/atom/ns#" term="ADFS" /><category scheme="http://www.blogger.com/atom/ns#" term="WS-Federation" /><category scheme="http://www.blogger.com/atom/ns#" term="Binding" /><category scheme="http://www.blogger.com/atom/ns#" term="Claims" /><title>Custom ADFS Login Form for SharePoint 2010 Claims</title><content type="html">This week I've been involved in creating a custom login page for SharePoint 2010 to bypass the standard "select a login method" page for multi-mode claims-enabled web-applications. What we wanted was similar to the &lt;a href="http://blogs.msdn.com/b/jjameson/archive/2011/02/25/claims-login-web-part-for-sharepoint-server-2010.aspx"&gt;Claims Login Web Part for SharePoint Server 2010&lt;/a&gt; for Forms-Based Authentication (FBA) by Jeremy Jameson, but for a trusted ADFS 2.0 identity provider instead.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-jqTbLA9P4X4/TxqHWaxRXcI/AAAAAAAAAXs/uAaDDNxdgDA/s1600/sp2010_cba_login_selector.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="131" src="http://3.bp.blogspot.com/-jqTbLA9P4X4/TxqHWaxRXcI/AAAAAAAAAXs/uAaDDNxdgDA/s400/sp2010_cba_login_selector.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Having a custom login page allows you to stay in your site and avoid the&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/hh147177.aspx"&gt;passive STS authN redirect dance&lt;/a&gt; back and forth between SP and the ADFS STS for authentication. This requires you to use active mode (WS-Trust) rather than the passive mode used by SharePoint. Note that this active approach won't give you single sign-on, because you won't get the MSISAuth&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/hh446525.aspx"&gt;ADFS SSO cookies&lt;/a&gt;&amp;nbsp;- it will simply authenticate you first and then give you the SharePoint FedAuth cookie.&lt;br /&gt;
&lt;br /&gt;
The code you need to call ADFS to make it authenticate you, and thus issue a claims token for use with SharePoint, can be found at &lt;a href="http://www.leastprivilege.com/UsingAnActiveEndpointToSignIntoAWebApplication.aspx"&gt;Using an Active Endpoint to sign into a Web Application&lt;/a&gt;&amp;nbsp;by Dominick Baier or &lt;a href="http://koenwillemse.wordpress.com/2010/08/02/making-a-web-application-use-an-active-sts/"&gt;Making a web application use an active STS&lt;/a&gt; by Koen Willemse. The missing detail not shown in their code is the URL to the ADFS endpoint, which needs to match the &lt;a href="http://www.leastprivilege.com/WIFADFS2AndWCFndashPart1Overview.aspx"&gt;chosen client credentials and security mode&lt;/a&gt;; when using &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;UserNameWSTrustBinding&lt;/span&gt;&amp;nbsp;and sending the username and password in the WCF message secured using SSL (i.e. mixed), the URL should be like "&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;http://adfs.pzl/adfs/services/trust/13/usernamemixed/&lt;/span&gt;" including the important ending / slash to avoid "405 method not allowed" error from IIS.&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; btnLogin_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// authenticate with WS-Trust endpoint&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; factory = &lt;span class="kwrd"&gt;new&lt;/span&gt; WSTrustChannelFactory(&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;new&lt;/span&gt; UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;new&lt;/span&gt; EndpointAddress(&lt;/pre&gt;
&lt;pre&gt;&lt;span class="str"&gt;"https://adfs.puzzlepart.com/adfs/services/trust/13/usernamemixed/"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    factory.Credentials.UserName.UserName = txtUserName.Text;&lt;/pre&gt;
&lt;pre&gt;    factory.Credentials.UserName.Password = txtPassword.Text;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; channel = factory.CreateChannel();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; rst = &lt;span class="kwrd"&gt;new&lt;/span&gt; RequestSecurityToken&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        RequestType = RequestTypes.Issue,&lt;/pre&gt;
&lt;pre class="alt"&gt;        AppliesTo = &lt;span class="kwrd"&gt;new&lt;/span&gt; EndpointAddress(&lt;span class="str"&gt;"urn:sharepoint:puzzlepart"&lt;/span&gt;),&lt;/pre&gt;
&lt;pre&gt;        KeyType = KeyTypes.Bearer&lt;/pre&gt;
&lt;pre class="alt"&gt;    };&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; genericToken = channel.Issue(rst) &lt;span class="kwrd"&gt;as&lt;/span&gt; GenericXmlSecurityToken;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// parse token&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; handlers = FederatedAuthentication.ServiceConfiguration&lt;/pre&gt;
&lt;pre class="alt"&gt;.SecurityTokenHandlers;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; token = handlers.ReadToken(&lt;span class="kwrd"&gt;new&lt;/span&gt; XmlTextReader(&lt;/pre&gt;
&lt;pre class="alt"&gt;       &lt;span class="kwrd"&gt;new&lt;/span&gt; StringReader(genericToken.TokenXml.OuterXml)));&lt;/pre&gt;
&lt;pre&gt;         &lt;/pre&gt;
&lt;pre class="alt"&gt;    SPSecurity.RunWithElevatedPrivileges(&lt;span class="kwrd"&gt;delegate&lt;/span&gt;(){&lt;/pre&gt;
&lt;pre&gt;        SPFederationAuthenticationModule.Current&lt;/pre&gt;
&lt;pre&gt;.&lt;span style="background-color: transparent;"&gt;SetPrincipalAndWriteSessionToken(token);&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    });&lt;/pre&gt;
&lt;pre&gt;    Response.Redirect(&lt;span class="str"&gt;"~/pages/default.aspx"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
After getting authenticated against the ADFS STS when calling &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Issue&lt;/span&gt;&amp;nbsp;on the WS-Trust channel with a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;RequestSecurityToken&lt;/span&gt;, the returned SAML security token must first be parsed and&amp;nbsp;then written to a FedAuth cookie created from the SAML token. The SharePoint FAM wrapper will both set the thread principal and write the cookie, making the user a logged in SharePoint user.&lt;br /&gt;
&lt;br /&gt;
Note how the writing of the cookie is wrapped with&amp;nbsp;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;RunWithElevatedPrivileges&lt;/span&gt; to ensure that &amp;nbsp;it runs as the app-pool identity and not as the impersonated SharePoint user. This is to avoid the dreaded "&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;CryptographicException: The system cannot find the file specified&lt;/span&gt;" error in the internal &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ProtectedDataCookieTransform&lt;/span&gt;&amp;nbsp;call.&lt;br /&gt;
&lt;br /&gt;
When calling&amp;nbsp;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ValidateToken&lt;/span&gt; you will run into the &lt;a href="http://blogs.msdn.com/b/jimmiet/archive/2010/09/19/10064794.aspx"&gt;SecurityTokenException: Issuer of the Token is not a Trusted Issuer&lt;/a&gt; error if your STS is not trusted by SharePoint. SharePoint is configured to use its own &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SPPassiveIssuerNameRegistry&lt;/span&gt;&amp;nbsp;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;/span&gt;and that will either validate against the built-in SharePoint STS or the set of trusted STS token issuers. See how to add your STS certificate(s)&amp;nbsp;at &lt;a href="http://blogs.msdn.com/b/ekraus/archive/2010/03/22/sharepoint-2010-claims-based-auth-with-adfs-v2.aspx"&gt;SharePoint 2010 Claims-Based Auth with ADFS v2&lt;/a&gt; by Eric Kraus. The trusted providers are apparently only used if the login page is located under the /_trust/ folder that is part of the above "redirect dance" when authenticating against a trusted identity provider.&lt;br /&gt;
&lt;br /&gt;
Over at &lt;a href="http://stackoverflow.com/questions/8215037/creating-an-custom-active-sts-for-sharepoint-2010-using-windows-identity-foundat"&gt;stack overflow&lt;/a&gt;,&amp;nbsp;Matt Whetton had run into the same exception as us and solved it by replacing the passive &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;issuerNameRegistry&amp;gt;&lt;/span&gt; with the Windows Identity Foundation (WIF) &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ConfigurationBasedIssuerNameRegistry&lt;/span&gt; instead. The&amp;nbsp;&lt;a href="http://koenwillemse.wordpress.com/2010/09/02/configuration-of-wif/"&gt;Configuration of WIF&lt;/a&gt;&amp;nbsp;post shows how to add the set of certificate names and thumbprints to the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;trustedIssuers&amp;gt;&lt;/span&gt; list. This is how your web.config list of trusted STS token issuers may look like:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;issuerNameRegistry&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry,&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;  &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;trustedIssuers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;    &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;thumbprint&lt;/span&gt;&lt;span class="kwrd"&gt;="1337133713371337"&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="CN=adfs-puzzlepart"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;    &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;thumbprint&lt;/span&gt;&lt;span class="kwrd"&gt;="0000000000000000"&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="CN=SharePoint Security Token Service"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;  &amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;trustedIssuers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;issuerNameRegistry&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Remember to add the SharePoint self-issued certificates such as the&amp;nbsp;"SharePoint Security Token Service" certificate&amp;nbsp;to the list of trusted issuers, in addition to your own STS.&lt;br /&gt;
&lt;br /&gt;
I strongly recommend putting your custom ADFS login page under /_trust/ to avoid having to change the SharePoint web.config files. We chose this approach to minimize risks.&lt;br /&gt;
&lt;br /&gt;
Note that Fiddler seems to break the ADFS login process, at least when decrypting SSL. The customized rule provided in &lt;a href="http://blogs.msdn.com/b/fiddler/archive/2011/09/04/fiddler-http-401-authentication-workaround-to-support-channel-binding-tokens-removing-endless-prompts.aspx"&gt;Fiddler and Channel Binding Tokens Revisited&lt;/a&gt;&amp;nbsp;by Eric Lawrence alleviates this problem. Just make sure you click "remember my credentials" when logging in so that Fiddler can get it from the Windows Credential Manager.&lt;br /&gt;
&lt;br /&gt;
Disclaimer: Note that even if things seems to work as normal after this configuration change, there is no guarantee that nothing was affected in the huge platform that SharePoint 2010 is. The combination of SP2010 claims and WIF is not very well documented, and any changes beyond supported configuration involves risks. Do not apply these changes if you are not sure that it will not break any of your SharePoint solutions or services.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-3117460831809973350?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/vBwRGpnrYQk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/3117460831809973350/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=3117460831809973350" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3117460831809973350?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3117460831809973350?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/vBwRGpnrYQk/sharepoint-adfs-custom-login-form.html" title="Custom ADFS Login Form for SharePoint 2010 Claims" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-jqTbLA9P4X4/TxqHWaxRXcI/AAAAAAAAAXs/uAaDDNxdgDA/s72-c/sp2010_cba_login_selector.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/01/sharepoint-adfs-custom-login-form.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MBRXwyfip7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-7132900798176755973</id><published>2012-01-17T09:22:00.000+01:00</published><updated>2012-02-16T20:44:14.296+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-16T20:44:14.296+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Publishing" /><category scheme="http://www.blogger.com/atom/ns#" term="Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="WebPart" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="VisualStudio" /><title>Simple Feature Files Cleanup using Extension Methods</title><content type="html">As every seasoned SharePoint developer knows, deactivating a feature does not remove the files deployed by that feature. The deployed masterpages, web part pages, wiki pages, page layouts, web-part definitions, styling artifacts, etc files will stay in the target libraries - and they will not be overwritten on feature activation. Don't let Visual Studio 2010 trick you into believing otherwise.&lt;br /&gt;
&lt;br /&gt;
You have to delete those deployed files yourself in the FeatureDeactivating event. The classic approach is to delete the files one-by-one, but this is tedious and error-prone. The following is a set of extension methods that allows you to simply do this:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; FeatureDeactivating(SPFeatureReceiverProperties properties)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;     SPSite site = (SPSite) properties.Feature.Parent;&lt;/pre&gt;
&lt;pre&gt;     properties.Definition.DeleteFeatureFiles(&lt;span class="str"&gt;"MasterPages"&lt;/span&gt;, site.RootWeb);&lt;/pre&gt;
&lt;pre class="alt"&gt;     properties.Definition.DeleteFeatureWebPartFiles(site.RootWeb);&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
The code is an adaptation of Corey Roth's&amp;nbsp;&lt;a href="http://www.dotnetmafia.com/blogs/dotnettipoftheday/archive/2009/02/16/linq-to-xml-and-deleting-files-on-feature-deactivation.aspx"&gt;LINQ to XML and Deleting Files on Feature Deactivation&lt;/a&gt;, using extension methods and supporting cleanup of specific feature modules and all feature web-parts.&lt;/div&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.Core.SPExtentions&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SPFeatureDefinitionExtentions&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Module&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Path { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; Files { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DeleteFeatureFiles&lt;/pre&gt;
&lt;pre class="alt"&gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; SPFeatureDefinition spFeatureDefinition, &lt;span class="kwrd"&gt;string&lt;/span&gt; moduleName, SPWeb web)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            List&amp;lt;Module&amp;gt; modules = GetModuleFiles(spFeatureDefinition, moduleName);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Module module &lt;span class="kwrd"&gt;in&lt;/span&gt; modules)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                DeleteModuleFiles(module, web);&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DeleteFeatureWebPartFiles&lt;/pre&gt;
&lt;pre class="alt"&gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; SPFeatureDefinition spFeatureDefinition, SPWeb web)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            List&amp;lt;Module&amp;gt; modules = GetAllModuleFiles(spFeatureDefinition);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Module module &lt;span class="kwrd"&gt;in&lt;/span&gt; modules)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.Compare(module.Path, &lt;span class="str"&gt;"_catalogs/wp"&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;StringComparison.CurrentCultureIgnoreCase) == 0)&lt;/pre&gt;
&lt;pre class="alt"&gt;                    DeleteModuleFiles(module, web);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;Module&amp;gt; GetModuleFiles&lt;/pre&gt;
&lt;pre&gt;(SPFeatureDefinition spFeatureDefinition, &lt;span class="kwrd"&gt;string&lt;/span&gt; moduleName)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; elementsPath = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;@"{0}\FEATURES\{1}\{2}\Elements.xml"&lt;/span&gt;,&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;SPUtility.GetGenericSetupPath(&lt;span class="str"&gt;"Template"&lt;/span&gt;),&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;spFeatureDefinition.DisplayName, moduleName);&lt;/pre&gt;
&lt;pre class="alt"&gt;            XDocument elementsXml = XDocument.Load(elementsPath);&lt;/pre&gt;
&lt;pre&gt;            XNamespace sharePointNamespace = &lt;span class="str"&gt;"http://schemas.microsoft.com/sharepoint/"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;// get each module name and the files in it&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; moduleList =&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;from&lt;/span&gt; module &lt;span class="kwrd"&gt;in&lt;/span&gt; elementsXml.Root.Elements(sharePointNamespace + &lt;span class="str"&gt;"Module"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;                select &lt;span class="kwrd"&gt;new&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                {&lt;/pre&gt;
&lt;pre class="alt"&gt;                    Name = (module.Attributes(&lt;span class="str"&gt;"Name"&lt;/span&gt;).Any())&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;? module.Attribute(&lt;span class="str"&gt;"Name"&lt;/span&gt;).Value : &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;                    ModuleUrl = (module.Attributes(&lt;span class="str"&gt;"Url"&lt;/span&gt;).Any())&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;? module.Attribute(&lt;span class="str"&gt;"Url"&lt;/span&gt;).Value : &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class="alt"&gt;                    Files = module.Elements(sharePointNamespace + &lt;span class="str"&gt;"File"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;                };&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            List&amp;lt;Module&amp;gt; modules = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Module&amp;gt;();&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;// iterate through each module with files&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; module &lt;span class="kwrd"&gt;in&lt;/span&gt; moduleList)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                Module m = &lt;span class="kwrd"&gt;new&lt;/span&gt; Module()&lt;/pre&gt;
&lt;pre class="alt"&gt;                               {&lt;/pre&gt;
&lt;pre&gt;                                   Name = module.Name,&lt;/pre&gt;
&lt;pre class="alt"&gt;                                   Path = module.ModuleUrl&lt;/pre&gt;
&lt;pre&gt;                               };&lt;/pre&gt;
&lt;pre class="alt"&gt;                List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; files = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; fileElement &lt;span class="kwrd"&gt;in&lt;/span&gt; module.Files)&lt;/pre&gt;
&lt;pre class="alt"&gt;                {&lt;/pre&gt;
&lt;pre&gt;                    &lt;span class="kwrd"&gt;string&lt;/span&gt; filename = (fileElement.Attributes(&lt;span class="str"&gt;"Name"&lt;/span&gt;).Any())&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;? fileElement.Attribute(&lt;span class="str"&gt;"Name"&lt;/span&gt;).Value : fileElement.Attribute(&lt;span class="str"&gt;"Url"&lt;/span&gt;).Value;&lt;/pre&gt;
&lt;pre class="alt"&gt;                    files.Add(filename);&lt;/pre&gt;
&lt;pre&gt;                }&lt;/pre&gt;
&lt;pre class="alt"&gt;                m.Files = files;&lt;/pre&gt;
&lt;pre&gt;                modules.Add(m);&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; modules;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DeleteModuleFiles(Module module, SPWeb web)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; filename &lt;span class="kwrd"&gt;in&lt;/span&gt; module.Files)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(module.Path))&lt;/pre&gt;
&lt;pre&gt;                    web.GetFile(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"{0}/{1}"&lt;/span&gt;, module.Path, filename)).Delete();&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                    web.Files.Delete(filename);&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;Module&amp;gt; GetAllModuleFiles&lt;/pre&gt;
&lt;pre&gt;(SPFeatureDefinition spFeatureDefinition)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; moduleList = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Module&amp;gt;();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; modulesPath = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;@"{0}\FEATURES\{1}\",&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="str"&gt;SPUtility.GetGenericSetupPath("&lt;/span&gt;Template"),&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;spFeatureDefinition.DisplayName);&lt;/pre&gt;
&lt;pre class="alt"&gt;            DirectoryInfo folder = &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectoryInfo(modulesPath);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (DirectoryInfo moduleFolder &lt;span class="kwrd"&gt;in&lt;/span&gt; folder.GetDirectories())&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                moduleList.AddRange(GetModuleFiles(spFeatureDefinition, moduleFolder.Name));&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; moduleList;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Note that page layouts cannot simply be deleted if they are in use. Use code to revert the "GhostableInLibrary" files to the uncustomized (ghosted) feature files on disk in the SharePoint root [14].&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-7132900798176755973?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/NoYYELrai20" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/7132900798176755973/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=7132900798176755973" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7132900798176755973?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7132900798176755973?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/NoYYELrai20/sp2010-feature-files-cleanup-extension.html" title="Simple Feature Files Cleanup using Extension Methods" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/01/sp2010-feature-files-cleanup-extension.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcHQH04cCp7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-7111505068438894512</id><published>2012-01-03T14:11:00.000+01:00</published><updated>2012-02-16T20:53:51.338+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-16T20:53:51.338+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Publishing" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration" /><title>SharePoint 2010 Localized Publishing Web Template</title><content type="html">When you try to create a new localized publishing site based on a minimal SharePoint 2010 publishing &lt;a href="http://blogs.msdn.com/b/vesku/archive/2010/10/14/sharepoint-2010-and-web-templates.aspx"&gt;web template&lt;/a&gt; (or a similar &lt;a href="http://www.andrewconnell.com/blog/archive/2008/12/06/Using-a-Minimal-Publishing-Site-Definition-in-the-field.aspx"&gt;minimal site definition&lt;/a&gt;), it might fail with a "CreateWelcomePage" error such as this:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;System.Runtime.InteropServices.COMException (0x80070001): 0x80070001 at &lt;/pre&gt;
&lt;pre&gt;Microsoft.SharePoint.Library.SPRequestInternalClass.GetMetadataForUrl&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;(String bstrUrl,&amp;nbsp;&lt;/span&gt;&lt;span style="background-color: transparent;"&gt;Int32 METADATAFLAGS, Guid&amp;amp; pgListId, Int32&amp;amp; plItemId,&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;Int32&amp;amp; plType, Object&amp;amp; pvarFileOrFolder) at &lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;Microsoft.SharePoint.Library.SPRequest.GetMetadataForUrl&lt;/pre&gt;
&lt;pre class="alt"&gt;(String bstrUrl, Int32 METADATAFLAGS,&lt;span style="background-color: transparent;"&gt; Guid&amp;amp; pgListId, Int32&amp;amp; plItemId,&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span style="background-color: transparent;"&gt;Int32&amp;amp; plType, Object&amp;amp; pvarFileOrFolder) -&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;-- End of inner exception stack trace --- at &lt;/pre&gt;
&lt;pre&gt;Microsoft.SharePoint.SPGlobal.HandleComException(COMException comEx)&lt;/pre&gt;
&lt;pre class="alt"&gt;  at &lt;/pre&gt;
&lt;pre&gt;Microsoft.SharePoint.Library.SPRequest.GetMetadataForUrl&lt;/pre&gt;
&lt;pre&gt;(String bstrUrl, Int32 METADATAFLAGS,&lt;span style="background-color: transparent;"&gt; Guid&amp;amp; pgListId, Int32&amp;amp; plItemId,&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style="background-color: transparent;"&gt;Int32&amp;amp; plType, Object&amp;amp; pvarFileOrFolder) at &lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;Microsoft.SharePoint.SPWeb.GetListItem&lt;/pre&gt;
&lt;pre class="alt"&gt;(String strUrl, Boolean bFields, String[] fields) at &lt;/pre&gt;
&lt;pre&gt;Microsoft.SharePoint.Publishing.PublishingWeb.GetPublishingPage(String strUrl) at &lt;/pre&gt;
&lt;pre class="alt"&gt;Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.CreateWelcomePage&lt;/pre&gt;
&lt;pre class="alt"&gt;(PublishingWeb area, PageLayout pageLayout) at &lt;/pre&gt;
&lt;pre&gt;Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.SetDefaultPageProperties&lt;/pre&gt;
&lt;pre&gt;(PublishingWeb area, Boolean&amp;amp; updateRequired) at &lt;/pre&gt;
&lt;pre class="alt"&gt;Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.&lt;/pre&gt;
&lt;pre class="alt"&gt;InitializePublishingWebDefaults()&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;- -- End of inner exception stack trace --- at &lt;/pre&gt;
&lt;pre&gt;Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.&lt;/pre&gt;
&lt;pre&gt;InitializePublishingWebDefaults() at &lt;/pre&gt;
&lt;pre class="alt"&gt;Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.Provision()&lt;/pre&gt;
&lt;pre&gt;  at &lt;/pre&gt;
&lt;pre class="alt"&gt;Microsoft.SharePoint.Publishing.PublishingFeatureHandler.&amp;lt;&amp;gt;c_DisplayClass3.b_0() at &lt;/pre&gt;
&lt;pre&gt;Microsoft.Office.Server.Utilities.CultureUtility.RunWithCultureScope&lt;/pre&gt;
&lt;pre&gt;(CodeToRunWithCultureScope code) at &lt;/pre&gt;
&lt;pre class="alt"&gt;Microsoft.SharePoint.Publishing.CmsSecurityUtilities.RunWithWebCulture&lt;/pre&gt;
&lt;pre class="alt"&gt;(SPWeb web, CodeToRun webCultureDependentCode) at &lt;/pre&gt;
&lt;pre&gt;Microsoft.SharePoint.Publishing.PublishingFeatureHandler.FeatureActivated&lt;/pre&gt;
&lt;pre&gt;(SPFeatureReceiverProperties receiverProperties).&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The typical cause is that your web template/site definition is a bit too minimal. The "Publishing" feature needs some initial configuration property data during feature activation. Don't strip these properties away completely. Also, activating the "Publishing" feature from code or a feature stapler will not work for localized sites if you don't pass in this configuration. It is not standard, but you can pass property XML data from code to feature activation as shown in&amp;nbsp;&lt;a href="http://hristopavlov.wordpress.com/2008/07/15/specifying-properties-when-activating-features-through-code/"&gt;Specifying Properties When Activating Features Through Code&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
You must pass in the publishing feature property configuration for the "WelcomePageUrl" to ensure that is reference the localized pages library during activation, which is /sider/ for LCID 1044. The fallback for when this property is not set or is empty seems to be hardcoded to /pages/. Note that using "osrvcore" as the resource file is needed for some languages if you don't have SP1 of the language pack installed.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Feature: Publishing --&amp;gt;&lt;/span&gt;        &lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Feature&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;="22A9EF51-737B-4ff2-9346-694633FE4416"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;  &lt;/pre&gt;
&lt;pre class="alt"&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Properties&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/sharepoint/"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Property&lt;/span&gt; &lt;span class="attr"&gt;Key&lt;/span&gt;&lt;span class="kwrd"&gt;="ChromeMasterUrl"&lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="attr"&gt;              Value&lt;/span&gt;&lt;span class="kwrd"&gt;="~SiteCollection/_catalogs/masterpage/puzzlepart.master"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Property&lt;/span&gt; &lt;span class="attr"&gt;Key&lt;/span&gt;&lt;span class="kwrd"&gt;="WelcomePageUrl"&lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="attr"&gt;              Value&lt;/span&gt;&lt;span class="kwrd"&gt;="$Resources:cmscore,List_Pages_UrlName;/default.aspx"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
It is important to reference an existing page in an existing library as the welcome page (home page). Deploy a page using a module if needed. Note that not all of these properties need to be specified as they have working default settings as fallback.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-7111505068438894512?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/EMLJA8Rd_1Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/7111505068438894512/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=7111505068438894512" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7111505068438894512?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7111505068438894512?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/EMLJA8Rd_1Y/sp2010-localized-publishing-web.html" title="SharePoint 2010 Localized Publishing Web Template" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2012/01/sp2010-localized-publishing-web.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04DQX46eCp7ImA9WhRUEUk.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-5131464118684414278</id><published>2011-11-01T11:19:00.002+01:00</published><updated>2012-01-21T12:39:30.010+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-21T12:39:30.010+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Search" /><category scheme="http://www.blogger.com/atom/ns#" term="Findability" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="IA" /><category scheme="http://www.blogger.com/atom/ns#" term="Taxonomy" /><category scheme="http://www.blogger.com/atom/ns#" term="SiteStructure" /><category scheme="http://www.blogger.com/atom/ns#" term="SearchDriven" /><category scheme="http://www.blogger.com/atom/ns#" term="Innovation" /><title>SharePoint Information Architecture from the Field</title><content type="html">Over the years, I've written quite a few articles on how to technically &lt;a href="http://kjellsj.blogspot.com/2010/08/classification-and-structuring-of.html"&gt;structure your SharePoint solutions&lt;/a&gt; into web-apps, sites, subsites, lists and document libraries. All based on having a defined Information Architecture (IA) as a basis for the solution design, or at least being able to reason about your content management using my&amp;nbsp;&lt;a href="http://kjellsj.blogspot.com/2011/10/sharepoint-2010-information.html"&gt;"chest of drawers" and "news paper"&lt;/a&gt;&amp;nbsp;analogies. The latter is based on my experiences from the field as most companies don't have a well-defined IA in place.&lt;br /&gt;
&lt;br /&gt;
Common questions from customers are "what is Information Architecture?" and "what is the value of having an IA for SharePoint, can't we just create sites and doc-libs on the fly as needed?". Not to forget "how do we go about creating an Information Architecture for SharePoint?". So here are some IA advice from Puzzlepart projects:&lt;br /&gt;
&lt;br /&gt;
In short, &lt;a href="http://kjellsj.blogspot.com/2005/05/sharepoint-areas-and-topics-for.html"&gt;Information Architecture defines how to classify and structure your content&lt;/a&gt; so that it is easy for content consumers to find and explore relevant content, while making it simple for workers to contribute and manage content in an efficient manner.&lt;br /&gt;
&lt;br /&gt;
The business goal of having an Information Architecture for your SharePoint solution is enabling workers
to contribute, store and mange content in a manner that is simple and
efficient, enabling more content sharing; and at the same time making it easy
for workers to browse and find content they need, while also making it easy for
workers to discover and explore relevant content they didn't know of. The
outcome is more knowledgeable workers that are better informed about what’s
going on in the company and about the range of intellectual property possessed
by other employees, while also saving time wasted on finding information, and
time wasted on incorrect or outdated information.&lt;o:p&gt;&lt;/o:p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;An outcome is a metric that customers use to define the successful realization 
of the objectives and goals. Outcomes happens after the project has delivered on 
its objectives and goals, and the customers must themselves work against 
securing the outcomes to achieve the desired business value.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
The business value of having a working IA is capturing company
knowledge from employees with better quality of shared content, which combined
with good findability drive &lt;a href="http://www.amazon.com/Power-Pull-Smartly-Things-Motion/dp/0465019358/"&gt;more knowledgeable workers that make better decisions and better faster processes&lt;/a&gt;. In addition, more and better content
sharing helps user not only discover and explore content, but also people such
as subject matter experts, allowing employees to build and expand their network
throughout the company, helping the company to retain talented employees
through social ties and communities. Access to discover more and better content
and people expertise is central to enabling innovation and process improvement,
as new knowledge is a trigger for new ideas and for identifying new
opportunities.&lt;br /&gt;
&lt;br /&gt;
The process of defining your IA for your SharePoint solution should focus on these objectives and goals:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Analyze and define the &lt;u&gt;content classification and structure&lt;/u&gt; for the solution&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: identify what content to manage and plan how to store it in SP, leading to sites, subsites and doc-lib structure organized into SP web-apps&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Analyze and define how to &lt;u&gt;browse and navigate&lt;/u&gt; the content&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: make it simple and efficient for users to find and use known content that they need in they daily work to drive better faster processes&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Analyze and define how to &lt;u&gt;discover and explore&lt;/u&gt; the content&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: make it easy for users to stumble upon novel shared knowledge based on "common focus" to trigger innovation and build social ties&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Provide simple and efficient &lt;u&gt;content contributor experience&lt;/u&gt;&amp;nbsp;with liberal appliance of default metadata values, storing content close to the authors&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: &lt;b&gt;make workers contributors, not knowledge management grunts&lt;/b&gt;, and help them store content correctly with better metadata and tagging, driving findability and "common focus" content discovery; drive better sharing and collaboration&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Analyze and define the &lt;u&gt;starter content types with metadata and term set taxonomy&lt;/u&gt; based on the defined site and doc-lib architecture, with a strong focus on needed search experience capabilities&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: enable content management and support&amp;nbsp;both search-driven and "common focus" content;&amp;nbsp;drive findability, sharing and innovation&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Analyze and define the &lt;u&gt;policies for social tagging and rating&lt;/u&gt; in the solution, also in relation to user profile interests, skills and responsibility tagging&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: drive "common focus" content discovery, drive findability, drive social communities, drive innovation&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Analyze and define the &lt;u&gt;search experience&lt;/u&gt;, focusing on both search-driven content and on search center scopes and refiners&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: drive findability and provide both search-driven and "common focus" content&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Enable &lt;u&gt;disposition of redundant and irrelevant content&lt;/u&gt;&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;goal: provide users with better, correct and up-to-date information, drive findability, save storage cost, save process cost&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
Including the search experience helps you avoid an initial version of your IA with a too narrow scope, which is easy to do for a starter IA when e.g. analyzing only project collaboration needs or just the document types of an attachment-based intranet. It makes you focus on what you get out, not only what you put in.&lt;br /&gt;
&lt;br /&gt;
Note that navigation is not IA, its just one way to explore the content. Using navigation to structure your content is just reapplying the fileshare folder approach, which we all know doesn't work too good for findability and discovery. Navigation should not &lt;a href="http://kjellsj.blogspot.com/2010/08/classification-and-structuring-of.html"&gt;define the statical IA structure for the content&lt;/a&gt;, do a &lt;a href="http://kjellsj.blogspot.com/2005/05/sharepoint-areas-and-topics-for.html"&gt;LATCH&lt;/a&gt; analysis to model the possible IA structures, and choose one of them to define the statical IA structure. The site map is closer to define statical IA structure than navigation, still it is only good for logical IA structure and cannot be expected to be used directly as the physical IA structure in SharePoint.&lt;br /&gt;
&lt;br /&gt;
In an upcoming article I will give some practical advice from the field on how to define and realize the Information Architecture for your SharePoint solution in an agile fashion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-5131464118684414278?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/W0yj8QNEDUY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/5131464118684414278/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=5131464118684414278" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/5131464118684414278?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/5131464118684414278?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/W0yj8QNEDUY/sp2010-information-architecture.html" title="SharePoint Information Architecture from the Field" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/11/sp2010-information-architecture.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UGRXY-eip7ImA9WhRTEUk.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-318456547476037539</id><published>2011-10-27T10:10:00.001+02:00</published><updated>2011-11-01T12:00:24.852+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-01T12:00:24.852+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="IA" /><category scheme="http://www.blogger.com/atom/ns#" term="Taxonomy" /><category scheme="http://www.blogger.com/atom/ns#" term="SiteStructure" /><title>SharePoint is like a Chest of Drawers</title><content type="html">I often get asked "how many document libraries and sites will we need?" in SharePoint, followed by "how will we know whether we should use more doc-libs in a site or just throw it all in there?" and "where should content be stored? we need to show it on the intranet home page, but it is really edited and owned by HR in region Gokk". Well, SharePoint is like a chest of drawers.&lt;br /&gt;
&lt;br /&gt;
To answer such questions, you need to know how to &lt;a href="http://kjellsj.blogspot.com/2010/08/classification-and-structuring-of.html"&gt;classify and structure your content&lt;/a&gt;; ideally you should have an &lt;a href="http://kjellsj.blogspot.com/2011/11/sp2010-information-architecture.html"&gt;Information Architecture&lt;/a&gt; for all your different kinds of data. If you are like most others, you don't. This is where the "chest of drawers" analogy might help you reason about your content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Whether you need many doc-libs or subsites or not depends on your IA policies for information management. Still don't have an IA? Think of a chest of drawers for you clothes: it makes it easier to manage different types of clothes in different ways at different schedules, by e.g. separating t-shirts from trousers. Maybe even handle different kinds of t-shirts differently, such as your precious Maiden t-shirts. It also allows for delegating a few drawers to be managed by your wife; maybe you even want to have some locked drawers with more privacy :)&lt;br /&gt;
&lt;br /&gt;
Your content are the clothes, the drawers are doc-libs or even subsites; and depending on the variety of clothes you have, you might need quite a sophisticated chest of drawers. Throw in all your other stuff, and you might need a bigger closet or a garage!&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-x6MA3Fxldd8/TqlOdyFcNbI/AAAAAAAAAXE/Q7wLJNNHq80/s1600/chest_of_drawers_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-x6MA3Fxldd8/TqlOdyFcNbI/AAAAAAAAAXE/Q7wLJNNHq80/s320/chest_of_drawers_02.jpg" width="239" /&gt;&lt;/a&gt;&lt;/div&gt;
So now all your content is stored into nicely separated drawers, with delegated and secure handling where needed. But is is not so easy to see what is in the drawers without actually opening and browsing the content of each drawer. Until we get one of those science fiction closets that knows whats in the drawers and let us explore what trendy outfits we can wear today, its time for another analogy: the good old news paper, even in its modern online incarnation.&lt;br /&gt;
&lt;br /&gt;
Think of a news paper with a front page and then multiple sections, such as domestic, foreign, sports, economics, etc.&amp;nbsp;The front page and section front pages are used to show the (elsewhere) stored content to readers, helping them quicly browse the content at wellknow locations in the paper. The shown stories are typically rollup content stored elsewhere, typically where maintained, close to the content editors.&lt;br /&gt;
&lt;br /&gt;
So a paper is built from dispersed storage of content that can be rolled up and targeted to readers multiple places. The home page and section pages rollup content "teasers" and allows the user to browse the content stored elsewhere in the paper and decide whether to explore it further.&lt;br /&gt;
&lt;br /&gt;
The front page is the home page of your SharePoint site, the sections are subsites and the section pages are the subsite welcome pages in SharePoint parlance. As for the drawers, there might be different management policies and different people handling the different sections, and this helps you decide when subsites are needed. The rollup, or cross publishing if you like, is achieved using the&amp;nbsp;content by query web-part or search-driven content based on content types, tagging and metadata.&lt;br /&gt;
&lt;br /&gt;
Controlled and secure management of content according to different policies and schedules is much simpler when using subsites as compared to throwing it all into one site. Store the content close to the producers, show it everywhere the users expect to find it - and also where *you* want them to discover and explore knowledge new to them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-318456547476037539?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/TAvHjSKtH5Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/318456547476037539/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=318456547476037539" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/318456547476037539?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/318456547476037539?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/TAvHjSKtH5Q/sharepoint-2010-information.html" title="SharePoint is like a Chest of Drawers" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-x6MA3Fxldd8/TqlOdyFcNbI/AAAAAAAAAXE/Q7wLJNNHq80/s72-c/chest_of_drawers_02.jpg" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/10/sharepoint-2010-information.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8CSXg_eip7ImA9WhdVFk8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-7704544294528811035</id><published>2011-09-08T12:45:00.003+02:00</published><updated>2011-09-21T19:57:48.642+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-21T19:57:48.642+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="MySite" /><category scheme="http://www.blogger.com/atom/ns#" term="UserProfile" /><title>Issue with SP2010 Personal Site UserInfo Synchronization</title><content type="html">Today we discovered an issue with the SharePoint synchronization from the user profile database to the hidden UserInfoList in all site-collections. This sync is performed by two timer jobs (see &lt;a href="http://community.bamboosolutions.com/blogs/sharepoint-2010/archive/2010/11/15/sharepoint-2010-user-management.aspx"&gt;profile sync details in this excellent article&lt;/a&gt; on the&amp;nbsp;Bamboo Team Blog), which will update changes to your user profile in all the cached profile data in the hidden user info lists, except for the UserInfoList in your personal site under the profile site (My Site Host).&lt;br /&gt;
&lt;br /&gt;
To verify the reported bug, I updated my mobile phone number in my user profile, and ran the two sync timer jobs. This is how my updated user information looks in a team-sites:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-oaEmuO4R2sc/Tmict2sbn3I/AAAAAAAAAW8/WbZ8EQOJwoo/s1600/UserInfoList_Synced.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="370" src="http://4.bp.blogspot.com/-oaEmuO4R2sc/Tmict2sbn3I/AAAAAAAAAW8/WbZ8EQOJwoo/s400/UserInfoList_Synced.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
And this is how my non-updated user information looks in my personal site:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-AsnKHdA2Tjo/TmibClcEpfI/AAAAAAAAAW4/hq-FbUgrI8U/s1600/UserInfoList_SyncIssue.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="371" src="http://2.bp.blogspot.com/-AsnKHdA2Tjo/TmibClcEpfI/AAAAAAAAAW4/hq-FbUgrI8U/s400/UserInfoList_SyncIssue.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
As you can see from the time stamps in the lower left corner, the profile data is still exactly as cached in the UserInfoList when I first created and visited my personal site. As of now I don't know any fix for this issue.&lt;br /&gt;
&lt;br /&gt;
[UPDATE] A list of things to check, not all applies to SP2010 though: &lt;a href="http://support.microsoft.com/kb/2388988"&gt;Troubleshooting User Profile Sync issues in Microsoft Office SharePoint Server 2007&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
As it turns out, all our personal sites get the "ProfileSynchronizationInternalException: ProfSynch: The site with ID &amp;lt;guid&amp;gt; cannot be synchronized due to an unprovisioned root web" error in the ULS. This seems to be a common problem in SharePoint 2010 according to this &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/sharepoint2010setup/thread/7e74bfe0-6adc-4337-ad2c-72226dba3581"&gt;MSDN forum thread&lt;/a&gt;, which also provides an unsupported workaround that updates the Flags column of the Webs table in the My Site Host content database.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-7704544294528811035?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/jZtVFXCA-LQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/7704544294528811035/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=7704544294528811035" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7704544294528811035?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7704544294528811035?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/jZtVFXCA-LQ/sp2010-personal-site-userinfo-profile.html" title="Issue with SP2010 Personal Site UserInfo Synchronization" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-oaEmuO4R2sc/Tmict2sbn3I/AAAAAAAAAW8/WbZ8EQOJwoo/s72-c/UserInfoList_Synced.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/09/sp2010-personal-site-userinfo-profile.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8CSXk_cCp7ImA9WhdXEEU.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-8361988759569362440</id><published>2011-08-10T09:58:00.004+02:00</published><updated>2011-08-23T10:07:48.748+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-23T10:07:48.748+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Customization" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="MySite" /><title>Some Gotchas when Customizing the "My Content" Personal Site</title><content type="html">Customizing an existing SharePoint 2010 site definition such as the personal site (SPSPERS) that provides the "My Content" section in the My Site Host web-application, is a bit different than customizing your own site definitions. As the supported way of customizing existing site definitions is to use feature stapling, you need to consider the provisioning order of elements in onet.xml and referenced and stapled 'SPSite' and 'SPWeb' features. Failing to do so might result in strange end results when creating a new site.&lt;br /&gt;
&lt;br /&gt;
The MCS Norway team has done a good job of documenting the SharePoint element provisioning order, as part of their &lt;a href="http://spsiteconfigurator.codeplex.com/"&gt;SiteConfigurator&lt;/a&gt; available at CodePlex:&lt;br /&gt;
&lt;blockquote&gt;"There are several steps in the creation process and SharePoint provisions in the following order:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Global onet.xml This file defines list templates for hidden lists, list base types, a default definition configuration, and modules that apply globally to the deployment.&lt;/li&gt;
&lt;li&gt;SPSite scoped features defined in site definitions onet.xml, in the order they are defined in the file. The onet.xml file defined in the site definition can define navigational areas, list templates, document templates, configurations, modules, components, and server e-mail footers used in the site definition to which it corresponds.&lt;/li&gt;
&lt;li&gt;SPSite scoped stapled features, in quasi random order&lt;/li&gt;
&lt;li&gt;SPWeb scoped features defined in onet.xml, in the order they are defined in the file.&lt;/li&gt;
&lt;li&gt;SPWeb scoped stapled features, in quasi random order&lt;/li&gt;
&lt;li&gt;List instances defined in onet.xml&lt;/li&gt;
&lt;li&gt;Modules defined in onet.xml&lt;/li&gt;
&lt;/ol&gt;This is a fairly complex process and it can often be hard to know the method for customizing a site definition. A solution can be right in one scenario and completely wrong in another, making this somewhat confusing."&lt;/blockquote&gt;Here are some gotchas related to SPSPERS customization:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;The doc-libs Shared Documents and Personal Documents do not exist yet during feature stapling; list instances in onet.xml are provisioned in step 6.&lt;/li&gt;
&lt;li&gt;The my content home page default.aspx&amp;nbsp;do not exist yet during feature stapling; files and pages in onet.xml are provisioned in step 7.&lt;/li&gt;
&lt;li&gt;Do not create your own customized default.aspx file, it will get filled with the standard web-parts when the file's &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;AllUsersWebParts&lt;/span&gt; are provisioned by the onet.xml module in step 7.&lt;/li&gt;
&lt;li&gt;The quick launch heading node titles are not yet localized during site provisioning, look them up by their id rather than their title when adding links&lt;/li&gt;
&lt;li&gt;The standard BlogView web-part only works when in a site page in the site root, it won't work in pages stored in lists, doc-libs or custom folders.&lt;/li&gt;
&lt;li&gt;The Wiki Page Home Page feature is not activated by default for personal sites; do not provision your own /SitePages/ custom list, doc-lib or folder, as this will prevent enabling wiki pages later on.&lt;/li&gt;
&lt;/ul&gt;To customize the standard personal site home page, you must provision a new home page with a different name and change the site's home page setting (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;SPFolder&amp;nbsp;rootFolder.WelcomePage&lt;/span&gt;). Remember to restore the standard setting when deactiving your customization feature.&lt;br /&gt;
&lt;br /&gt;
I strongly recommend using or learning from the SiteConfigurator, download the feature and the source code from CodePlex and join the community there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-8361988759569362440?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/K7mufjFUNEU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/8361988759569362440/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=8361988759569362440" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/8361988759569362440?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/8361988759569362440?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/K7mufjFUNEU/customizing-sharepoint-2010-my-content.html" title="Some Gotchas when Customizing the &quot;My Content&quot; Personal Site" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/08/customizing-sharepoint-2010-my-content.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYESHo_cSp7ImA9WhZaGUk.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-4132592628881493464</id><published>2011-07-06T08:26:00.005+02:00</published><updated>2011-07-06T12:28:29.449+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-06T12:28:29.449+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Topology" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration" /><category scheme="http://www.blogger.com/atom/ns#" term="FAST" /><category scheme="http://www.blogger.com/atom/ns#" term="ServiceApplications" /><title>Problem creating a FAST Content SSA in SharePoint 2010</title><content type="html">While installing Fast Search Server for SharePoint 2010 (FS4SP) on a dev farm today, I got a problem with the provisioning of a new FAST Content SSA (Search Service Application), it would hang forever at "0:01 Configuring the Search Service..." waiting for the TopologyConfigFinish.aspx page to complete.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-5DIvxJwc818/ThQWATzrSqI/AAAAAAAAAWY/3bvDncflMPQ/s1600/SP2010_create_new_SSA.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="128" src="http://3.bp.blogspot.com/-5DIvxJwc818/ThQWATzrSqI/AAAAAAAAAWY/3bvDncflMPQ/s400/SP2010_create_new_SSA.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The problem turned out to be that the SharePoint 2010 Administration service wasn't started after the mandatory server reboot after installing FS4SP. The FAST "nctrl status" cmdlet does not check this.&amp;nbsp;Make sure that both the SP2010 Administration and Timer services are running:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-CaPKDsSvohs/ThP9iVa3ejI/AAAAAAAAAWU/8FD9s3N27fE/s1600/SharePoint_Timer_Admin_NTServices.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="106" src="http://1.bp.blogspot.com/-CaPKDsSvohs/ThP9iVa3ejI/AAAAAAAAAWU/8FD9s3N27fE/s400/SharePoint_Timer_Admin_NTServices.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
If you still can't create new or delete search service application instances, or make topology changes at all, then you might need to delete the old SSA the hard way. See &lt;a href="http://donalconlon.wordpress.com/2010/08/27/deleting-the-search-service-application/"&gt;Deleteing the search service application&lt;/a&gt; and&amp;nbsp;&lt;a href="http://blogs.technet.com/b/nishants/archive/2010/04/14/how-to-delete-orphan-configuration-objects-from-sharepoint-farm.aspx"&gt;How to delete orphan configuration objects from SharePoint farm&lt;/a&gt;. Heed this warning: "Please be VERY careful when executing the deleteconfigurationobject command, if this command is not used in the correct way (if you end up deleting the wrong object) there is NO way to revert back the changes and it has the potential to render your Configuration Database useless, hence you may require to restore / rebuild your SharePoint farm".&lt;br /&gt;
&lt;br /&gt;
Remember to &lt;a href="http://technet.microsoft.com/nb-no/library/ff381261(en-us).aspx"&gt;configure SSL enabled communication&lt;/a&gt; again when recreating the FAST Content SSA, otherwise your next crawl will be stuck on starting while retrying every 60 seconds to connect to the document engine. Also remember to restart the FAST Search for SharePoint and the SharePoint Server Search 14 services before starting a new full crawl.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-4132592628881493464?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/lwmFO9qi3ec" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/4132592628881493464/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=4132592628881493464" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/4132592628881493464?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/4132592628881493464?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/lwmFO9qi3ec/search-service-application-sharepoint.html" title="Problem creating a FAST Content SSA in SharePoint 2010" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-5DIvxJwc818/ThQWATzrSqI/AAAAAAAAAWY/3bvDncflMPQ/s72-c/SP2010_create_new_SSA.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/07/search-service-application-sharepoint.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYDRH4zcSp7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-7011517746115939419</id><published>2011-06-24T12:23:00.027+02:00</published><updated>2012-02-16T20:56:15.089+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-16T20:56:15.089+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="AJAX" /><category scheme="http://www.blogger.com/atom/ns#" term="WebPart" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><title>Delay Loading of Data in SharePoint 2010 Web Parts</title><content type="html">Sometimes your web-parts may take a long time to load their data, e.g. when connecting to external data through BCS, doing SPSiteDataQuery across a large number of sites, or when iterating over a user's site memberships to read some items from lists in different site-collections. Put a few of such web-parts on a dashboard page and wait for the combined load time of all those web-parts to complete before the page is shown. Not a nice user experience. These days users expect something as shown in this short screencast:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/xyJ3cs-CBtA/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/xyJ3cs-CBtA?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;

&lt;param name="bgcolor" value="#FFFFFF" /&gt;

&lt;embed width="320" height="266"  src="http://www.youtube.com/v/xyJ3cs-CBtA?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;br /&gt;
If you've used ASP.NET Ajax UpdatePanels, you might wish to utilize the asynchronous partial page update experience seen on postbacks also during page load. The simple thing seems to be &lt;a href="http://encosia.com/easily-refresh-an-updatepanel-using-javascript/"&gt;calling __doPostBack&lt;/a&gt;&amp;nbsp;for each UpdatePanel from the &lt;a href="http://encosia.com/document-ready-and-pageload-are-not-the-same/"&gt;page load&lt;/a&gt; JavaScript event to trigger the Ajax async partial postback. That won't work, as only one concurrent postback is allowed by ASP.NET Ajax, so only one of your web-parts will work as expected, the other __doPostBack calls will get canceled by the ScriptManager.&lt;br /&gt;
&lt;br /&gt;
A simple solution to this problem, is to put an &lt;a href="http://www.codeproject.com/KB/ajax/DelayedContentLoading.aspx"&gt;asp:timer control inside the UpdatePanel&lt;/a&gt; and let it trigger a postback to your web-part code. Then load the data and update the content of the UpdatePanel during this async Ajax postback.&lt;br /&gt;
&lt;br /&gt;
Here are the code to two base classes that implements this delayed load approach:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.UI;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.UI.WebControls;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Puzzlepart.SharePoint.WebParts&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AjaxPanelWebPart : System.Web.UI.WebControls.WebParts.WebPart&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; UpdatePanel AjaxPanel;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnLoad(EventArgs e)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnLoad(e);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.EnsureChildControls();&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            AjaxPanel = &lt;span class="kwrd"&gt;new&lt;/span&gt; UpdatePanel()&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                ID = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ID + &lt;span class="str"&gt;"UpdatePanel1"&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class="alt"&gt;                UpdateMode = UpdatePanelUpdateMode.Conditional&lt;/pre&gt;
&lt;pre&gt;            };&lt;/pre&gt;
&lt;pre class="alt"&gt;            Controls.Add(AjaxPanel);&lt;/pre&gt;
&lt;pre&gt;            UpdatePanelConfigurator.AddUpdatePanelProgress(AjaxPanel);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ApplyUserActions()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//to be overridden in derived classes&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RebindControlsWhenNoViewState()&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (Page.IsPostBack == &lt;span class="kwrd"&gt;true&lt;/span&gt; &amp;amp;&amp;amp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            System.Web.UI.ScriptManager.GetCurrent(Page).IsInAsyncPostBack == &lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                ApplyUserActions();&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AjaxPanelDelayedLoadWebPart : AjaxPanelWebPart&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; Timer LoadTimer;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnLoad(EventArgs e)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnLoad(e);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.EnsureChildControls();&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.CreateChildControls();&lt;/pre&gt;
&lt;pre&gt;            CreateLoadTimer();&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateLoadTimer()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            LoadTimer = &lt;span class="kwrd"&gt;new&lt;/span&gt; Timer()&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                ID = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ID + &lt;span class="str"&gt;"LoadTimer1"&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;                Interval = 1 &lt;span class="rem"&gt;//millisecond&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            };&lt;/pre&gt;
&lt;pre&gt;            LoadTimer.Tick += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;gt;(LoadTimer_Tick);&lt;/pre&gt;
&lt;pre class="alt"&gt;            AjaxPanel.ContentTemplateContainer.Controls.Add(LoadTimer);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LoadTimer_Tick(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            LoadTimer.Enabled = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                ApplyUserActions();&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                Label msg = &lt;span class="kwrd"&gt;new&lt;/span&gt; Label()&lt;/pre&gt;
&lt;pre&gt;                {&lt;/pre&gt;
&lt;pre class="alt"&gt;                    Text = &lt;span class="str"&gt;"An error occurred in delayed load: "&lt;/span&gt; + ex.Message,&lt;/pre&gt;
&lt;pre&gt;                    ToolTip = ex.ToString()&lt;/pre&gt;
&lt;pre class="alt"&gt;                };&lt;/pre&gt;
&lt;pre&gt;                Controls.Add(msg);&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ApplyUserActions&lt;/span&gt; method is where you should fetch your data and update the content of the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;AjaxPanel&lt;/span&gt; member control. All the controls of your web-part should be created as usual, remember to call &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;base.CreateChildControls&lt;/span&gt;&amp;nbsp;in your derived web-parts to ensure that the Ajax controls get created.&lt;br /&gt;
&lt;br /&gt;
Note that no slow data must be fetched and bound to your web-part controls during page load, e.g. in the&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;CreateChildControls&lt;/span&gt; or &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;OnPreRender&lt;/span&gt; methods, as this defeats the purpose of delay loading the data in the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ApplyUserActions&lt;/span&gt; async postback method. A typical scenario is creating and configuring an SPGridView control in &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;CreateChildControls&lt;/span&gt; and then fetch the data and set the grid's DataSource and call the grid's DataBind method in the overridden &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ApplyUserActions&lt;/span&gt; method in your derived web-part.&lt;br /&gt;
&lt;br /&gt;
Note that &lt;a href="http://encosia.com/are-you-making-these-3-common-aspnet-ajax-mistakes/"&gt;all page event code get executed on partial postbacks&lt;/a&gt; for all web-parts on the page. This can cause problems that are unrelated to the web-part that triggers the postback, manifested as ScriptResource.axd JavaScript errors. Some problems are related to viewstate handling, such as the "Error=Value cannot be null.  Parameter name: container" SPGridView exception. The simple solution is to turn off viewstate, and then call the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;RebindControlsWhenNoViewState &lt;/span&gt; method to load and bind the data when the postback is not an async Ajax postback. This must also be done for all controls that do not use viewstate, otherwise they will end up empty after e.g. modal dialogs that reload the page on close.&lt;br /&gt;
&lt;br /&gt;
This ASP.NET Timer approach allows the page to load quickly, then each web-part will in turn get the timer tick postback and update itself using &lt;a href="http://msdn.microsoft.com/en-us/library/bb399001.aspx"&gt;ASP.NET Ajax partial page updates&lt;/a&gt;. Note that this code won’t work as a sandboxed web-part. The UpdatePanel control requires the ScriptManager, which isn’t accessible from the sandboxed worker process.&lt;br /&gt;
&lt;br /&gt;
The more professional way of getting real asynchronous loading for web-part content is to use &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;PageAsyncTask&lt;/span&gt; as shown in Chapter 9 in Wictor Wilen's excellent &lt;a href="http://www.amazon.com/SharePoint-2010-Web-Parts-Action/dp/1935182773"&gt;SharePoint 2010 Web Parts in Action&lt;/a&gt; book. It does require a bit more code, but will allow parallell data fetching and thus faster page load time. It also works without using any UpdatePanels as all is done server-side.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-7011517746115939419?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/dKzRN-VWNtg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/7011517746115939419/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=7011517746115939419" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7011517746115939419?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7011517746115939419?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/dKzRN-VWNtg/delayed-load-sharepoint-2010-web-parts.html" title="Delay Loading of Data in SharePoint 2010 Web Parts" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/06/delayed-load-sharepoint-2010-web-parts.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQGSHczeyp7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-6054956174669236051</id><published>2011-05-19T20:18:00.018+02:00</published><updated>2012-02-16T20:58:49.983+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-16T20:58:49.983+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ContentType" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Taxonomy" /><category scheme="http://www.blogger.com/atom/ns#" term="Governance" /><category scheme="http://www.blogger.com/atom/ns#" term="ContentTypeHub" /><category scheme="http://www.blogger.com/atom/ns#" term="ManagedMetadataService" /><title>New Sites and the SharePoint 2010 Content Type Hub</title><content type="html">The SharePoint 2010 content type hub does quite a good job of managing and publishing a centrally controlled set of content types. There are a few quirks and limitations, some of them documented in &lt;a href="http://blogs.msdn.com/b/chaks/archive/2011/02/09/content-type-hub-limitations.aspx"&gt;Content Type Hub FAQ and Limitations&lt;/a&gt; by Chaks' SharePoint Corner; not to forget the &lt;a href="http://www.sharepointanalysthq.com/2010/06/content-type-publishing-in-sharepoint-2010/"&gt;content type publishing timer jobs&lt;/a&gt; that actually push the content types to the subscribers.&lt;br /&gt;
&lt;br /&gt;
One of the less documented areas of using a content type hub (HUB) is what happens to new site-collections that are provisioned? What if I have list definitions in my features, how can I be sure that their referenced content types have been provisioned at feature activation time? Can I deploy my enterprise content types feature at both the hub site-collection and also at new site-collections that users create?&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-P55nO5mJZbg/TddqLWLSxfI/AAAAAAAAAWQ/UuS-3cg75JU/s1600/content+type+hub.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="209" src="http://2.bp.blogspot.com/-P55nO5mJZbg/TddqLWLSxfI/AAAAAAAAAWQ/UuS-3cg75JU/s320/content+type+hub.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
First, when a new site-collection is created, it will immediately have all the published content types from the parent SharePoint web-application's connected Managed Metadata Service (MMS) application's defined HUB, automatically provisioned into its local content type gallery. Note that this applies only to the published content types as configured in the source hub. Content types that are not published, will not exist in your new site-collection. Note that hub content types are not by default published; this must be configured for every single content type in the source hub.&lt;br /&gt;
&lt;br /&gt;
So if your list definitions depend on global content types that have not been published in the HUB, your feature activation will fail. You can of course solve this by publishing the applicable global content types in the source hub and run the timer jobs first, as this will ensure that new site-collections will have the enterprise content types auto-provisioned from the MMS HUB.&lt;br /&gt;
&lt;br /&gt;
However, you can also deploy your enterprise content types feature to both the content type hub and to any other site-collection that you create. This works fine as the site content type definitions are identical, including the &lt;a href="http://msdn.microsoft.com/en-us/library/aa543822.aspx"&gt;content type ID&lt;/a&gt; structure - after all it is the same content type CAML feature. This won't affect subscribing to the content type hub, and publishing new, updated or derived content types from the hub works just as expected.&lt;br /&gt;
&lt;br /&gt;
Activate your site content type feature before activating your list definition feature, or any other feature that depends on the site content types being provisioned, to ensure that they exists locally in the new site-collection even if not yet published in the HUB.&lt;br /&gt;
&lt;br /&gt;
As your taxonomy is subject to change, so are your enterprise content types. Thus, your deployment strategy for enterprise content types needs to handle change. I strongly recommend using the &lt;a href="http://kjellsj.blogspot.com/2010/04/sharepoint-2010-open-closed-taxonomy.html"&gt;Open-Closed Principle for modifying and extending the enterprise content types&lt;/a&gt;. The Open-Closed Principle is based on using a set of immutable base content types that you derive from to make new specialized content types, inheriting fields from the base. The immutable base of the Open-Closed Principle coincides nicely with provisioning global content types through both a feature and the content type hub, as by policy any changes are made by extending the former through the latter.&lt;br /&gt;
&lt;br /&gt;
Even trivial stuff such as providing standardized company templates for Word and  other Office applications, is best done by publishing new derived  content types. Use the content type hub to inherit your base PzlDocument into PzlDocumentMemo and attach a template, go to "Manage publishing for this content type" to publish the content type. Wait for, or run, the two HUB timer jobs, and then add the Word template to the applicable document libraries.&lt;br /&gt;
&lt;br /&gt;
Now you're in for a surprise later on. The next time you try to create a new site-collection after publishing modifications in the HUB, you might get this "content type is read only" error:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-LUGSEyedK4M/TdVTGu-NYKI/AAAAAAAAAWM/dB0pg0wBDRA/s1600/SharePoint_content_type_hub_update_error.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="156" src="http://4.bp.blogspot.com/-LUGSEyedK4M/TdVTGu-NYKI/AAAAAAAAAWM/dB0pg0wBDRA/s320/SharePoint_content_type_hub_update_error.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The ULS log typically contains an exception like this:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SPContentTypeReadOnlyException&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Error code: -2146232832&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;The content type is read only or updateChildren is true and one of the child objects of the content type is read only.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The root cause for this is that published content types are by default read-only in the subscribers. What typically leads to this error is the need to use code when provisioning content types, e.g. when renaming and reordering fields, or when adding the enterprise keywords field to your content type. Another typical scenario where code is required is managed metadata fields; see &lt;a href="http://www.wictorwilen.se/Post/How-to-provision-SharePoint-2010-Managed-Metadata-columns.aspx"&gt;How to provision SharePoint 2010 Managed Metadata columns&lt;/a&gt; by Wictor Wilén.&lt;br /&gt;
&lt;br /&gt;
Making changes to the site content type definition in the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;FeatureActivated&lt;/span&gt; code and then calling &lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SPContentType Update&lt;/span&gt;&lt;/span&gt; with &lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;updateChildren=true&lt;/span&gt;&lt;/span&gt; will work fine, until someone creates a new derived content type in the source hub and publish it. Your carefully tested code will suddenly crash, as the published child content type is read-only! Alas, what better proof that the deployed and the published global content types are the same?&lt;br /&gt;
&lt;br /&gt;
Luckily, the change is isolated to the new inherited content type, thus it can safely be ignored when deploying the base content types. Use this overloaded &lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Update&lt;/span&gt;&lt;/span&gt; method when modifying the global content types:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(&lt;/pre&gt;
&lt;pre&gt;         &lt;span class="kwrd"&gt;bool&lt;/span&gt; updateChildren := &lt;span class="kwrd"&gt;true&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class="alt"&gt;         &lt;span class="kwrd"&gt;bool&lt;/span&gt; throwOnSealedOrReadOnly := &lt;span class="kwrd"&gt;false&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The HUB change did not affect your global content type  due to using the Open-Closed governance policy for enterprise content types. See my &lt;a href="http://kjellsj.blogspot.com/2010/04/sharepoint-2010-open-closed-taxonomy.html"&gt;SharePoint 2010 Open-Closed Taxonomy&lt;/a&gt; post to learn more about this recommended policy.&lt;br /&gt;
&lt;br /&gt;
The content type hub and the Managed Metadata Service are perhaps the best new features in SharePoint 2010, still there are some uncharted areas that make developers reluctant at using the MMS HUB. There are a lot of articles at Technet and MSDN on the architecture, but way too little about deployment scenarios and issues such as those in this post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-6054956174669236051?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/kZMJnrXQ8DM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/6054956174669236051/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=6054956174669236051" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/6054956174669236051?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/6054956174669236051?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/kZMJnrXQ8DM/provisioning-sites-content-type-hub.html" title="New Sites and the SharePoint 2010 Content Type Hub" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-P55nO5mJZbg/TddqLWLSxfI/AAAAAAAAAWQ/UuS-3cg75JU/s72-c/content+type+hub.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/05/provisioning-sites-content-type-hub.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkAMRX44fCp7ImA9WhRVF0U.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-9215547244882883193</id><published>2011-05-07T19:53:00.023+02:00</published><updated>2012-01-17T09:26:24.034+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-17T09:26:24.034+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Search" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="InformationManagement" /><category scheme="http://www.blogger.com/atom/ns#" term="Governance" /><category scheme="http://www.blogger.com/atom/ns#" term="SearchDriven" /><title>Site Lifecycle Management using Retention Policies</title><content type="html">The ootb &lt;a href="http://kjellsj.blogspot.com/2010/05/start-with-simple-governance-sharepoint.html"&gt;governance tools for site lifecycle management&lt;/a&gt; (SLM) in SharePoint 2010 have not improved from the previous version. You're still stuck with the &lt;a href="http://technet.microsoft.com/en-us/library/cc262420.aspx"&gt;Site Use Confirmation and Deletion&lt;/a&gt; policies that will just periodically e-mail site owners and ask them to confirm that their site is still in use. There is no check for the site or its content actually being used, it is just a dumb timer job. If the site is not confirmed as still being active, the site will then be deleted - even if it is still in use. As deleting a site is not covered by any SharePoint recycle bin mechanism (&lt;a href="http://sharepoint.microsoft.com/blog/Pages/BlogPost.aspx?pID=973"&gt;coming in SP1&lt;/a&gt;), Microsoft also provides the &lt;a href="http://governance.codeplex.com/"&gt;site deletion capture tool&lt;/a&gt; on CodePlex.&lt;br /&gt;
&lt;br /&gt;
Wouldn't it be nice if we could apply the &lt;a href="http://office.microsoft.com/en-us/sharepoint-server-help/create-and-apply-information-management-policies-HA101631505.aspx"&gt;information management policies&lt;/a&gt; for retention and disposition of content also for SharePoint 2010 sites? Yes we can :) By using a content type to identify and keep metadata for a site, the standard information management policies for content expiration can be configured to implement a recurring multistage retention policy for site disposition.&lt;br /&gt;
&lt;br /&gt;
Create a site information content type and bind it to a list or library in your site definition, and ensure that this list contains one SiteInfo item with the metadata of the site. Typical metadata are site created date, site contact, site type, cost center, unit and department, is restricted site flag, last review date, next review date, and last update timestamp. Restrict edit permissions for this list to just site owners or admins.&lt;br /&gt;
&lt;br /&gt;
Enable retention for the SiteInfo content type to configure your site lifecycle management policy as defined in your &lt;a href="http://kjellsj.blogspot.com/2010/05/sharepoint-governance-part-i-eating.html"&gt;governance plan&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-_-LwqA6NK7o/TcVwNOsSW9I/AAAAAAAAAWA/8KUm_YXjtDA/s1600/SP2010_information_management_retention.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="281" src="http://3.bp.blogspot.com/-_-LwqA6NK7o/TcVwNOsSW9I/AAAAAAAAAWA/8KUm_YXjtDA/s400/SP2010_information_management_retention.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Add one or more retention stages for the SiteInfo content type as needed by your SLM policy. You will typically have a first stage that will start a workflow to notify the site owner of site expiration and ask for disposition confirmation. Make sure that the site owner knows about and enacts on your defined governance policies for manual information management, such as sending valuable documents to records management. Then there will be a second stage for performing the site disposition steps triggered by the confirmation.&lt;br /&gt;
&lt;br /&gt;
You can also implement custom information management policy &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.recordsmanagement.policyfeatures.iexpirationformula.aspx"&gt;expiration formula&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.recordsmanagement.policyfeatures.iexpirationaction.aspx"&gt;expiration action&lt;/a&gt; for use when configuring your retention policy. You typically do this when your policy requires retention events that are not based on date fields only. See Sahil Malik's &lt;a href="http://blah.winsmarts.com/2008-10-Authoring_custom_expiration_policies_and_actions_in_SharePoint_2007.aspx"&gt;Authoring custom expiration policies and actions in SharePoint 2007&lt;/a&gt; which is still valid for SharePoint 2010.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-RXEC1rxxxug/TcVxJOnn6yI/AAAAAAAAAWE/aWPadSfBTxs/s1600/SP2010_information_management_site_disposition.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="323" src="http://3.bp.blogspot.com/-RXEC1rxxxug/TcVxJOnn6yI/AAAAAAAAAWE/aWPadSfBTxs/s400/SP2010_information_management_site_disposition.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Use a &lt;b&gt;custom workflow&lt;/b&gt; or &lt;b&gt;custom expiration action&lt;/b&gt; to implement the site disposition steps: user removal, automated content clean-up and archiving, and finally trigger deletion of the site. If the site is automatically deleted by a custom workflow, or marked for deletion to be processed by a custom timer job, or a custom action just sends an e-mail to the site-admin, is up to your SLM policy.&lt;br /&gt;
&lt;br /&gt;
If you need to keep the site in a passive state for e.g. 6 months before deleting it, you can use a&amp;nbsp;delegate control in your site master pages to prevent access to passive sites or you can move the site to an archive web-app that use a "deny write" / "deny all" access policy to prevent access. Note that the former is not real security, just content targeting for the site. The latter is real security, as "deny" web-app policies overrides site specific access rights granted to SharePoint groups and users. This allows for keeping the site users and groups "as-is" in case the site can be reactivated again according to your SLM policies. If site owners can do housekeeping on a site while passive, then grant them access by creating extra "steward" accounts that are not subject to being denied access.&lt;br /&gt;
&lt;br /&gt;
I recommend removing all users from the default&amp;nbsp;&lt;a href="http://sharepointmagazine.net/articles/administrator/best-practices-for-sharepoint-groups"&gt;site members group&lt;/a&gt; before deleting the site, otherwise the site will not be deleted from the &lt;a href="http://blogs.msdn.com/b/spses/archive/2011/02/05/social-computing-part-4-colleagues-membership-and-more.aspx"&gt;site memberships&lt;/a&gt; list in the user's my site.&lt;br /&gt;
&lt;br /&gt;
The astute reader may wonder how the content type retention policy knows if the site is actually in use. The answer is quite simple; each SPWeb object provides a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;LastItemModifiedDate&lt;/span&gt; property. This timestamp is also stored in the &lt;a href="http://pbs2010.codeplex.com/"&gt;SharePoint property bag&lt;/a&gt;. Use a delegate control in your site's master page to check and push the timestamp to a date-time field the SiteInfo item, so that the rentention policy can trigger on it. Remember to use &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SystemUpdate&lt;/span&gt; when updating the SiteInfo, otherwise you will change the site's&amp;nbsp;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;LastItemModifiedDate&lt;/span&gt;&amp;nbsp;to now. You can also use a custom expiration formula that inspects the last modified timestamp for the site when the &lt;a href="http://technet.microsoft.com/en-us/library/cc678870.aspx"&gt;information management policy timer job&lt;/a&gt; runs.&lt;br /&gt;
&lt;br /&gt;
We also use the site information content type in our Puzzlepart projects to provide a search-driven site directory. It is quite simple to make a nicely categorized and searchable site catalog by simply using one or more&amp;nbsp;&lt;a href="http://www.zimmergren.net/archive/2008/03/15/moss-2007-customize-the-search-result-using-xslt-part-3-customize-using-sharepoint-designer-2007.aspx"&gt;customized the search results&lt;/a&gt; web-parts. This search-driven catalog can of course be sorted by the search result 'write'  managed property, which must be mapped to the crawled property field  that contains the LastItemModifiedDate of a site.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-EeYNZO4IMN4/TceWNLIlrtI/AAAAAAAAAWI/h62UA7EzrB8/s1600/Search_Driven_SharePoint_Site_Directory.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="172" src="http://2.bp.blogspot.com/-EeYNZO4IMN4/TceWNLIlrtI/AAAAAAAAAWI/h62UA7EzrB8/s320/Search_Driven_SharePoint_Site_Directory.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Using a &lt;a href="http://kjellsj.blogspot.com/2010/08/my-tasks-web-part-search-driven-cross.html"&gt;search-driven approach&lt;/a&gt; makes it unnecessary to have a classic site directory list. The site metadata is simply stored directly in a list within each site, managed by the respective site owners. This is more likely to keep the site metadata up-to-date rather than going stale in a central site directory list that no one maintains.&lt;br /&gt;
&lt;br /&gt;
I hope this post have given you some new ideas on how to store, manage and use site metadata both for site lifecycle management and for providing a relevant search-driven site directory.&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-9215547244882883193?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/paBt2rEeIiQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/9215547244882883193/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=9215547244882883193" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/9215547244882883193?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/9215547244882883193?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/paBt2rEeIiQ/sharepoint-site-lifecycle-management.html" title="Site Lifecycle Management using Retention Policies" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-_-LwqA6NK7o/TcVwNOsSW9I/AAAAAAAAAWA/8KUm_YXjtDA/s72-c/SP2010_information_management_retention.png" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/05/sharepoint-site-lifecycle-management.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYESXc4fip7ImA9WhZXEks.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-3723730767773055960</id><published>2011-04-29T09:05:00.011+02:00</published><updated>2011-05-01T17:01:48.936+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-01T17:01:48.936+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SqlServer" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="SecureStoreService" /><category scheme="http://www.blogger.com/atom/ns#" term="BCS" /><title>Using SP2010 BCS Resource Files for BDC Model Settings</title><content type="html">You've probably seen way too many Business Connectivity Services (BCS) demos using SharePoint Designer (SPD), showing how simple it is to connect to a SQL Server 2008 database and automagically create external content types and operations, with external lists that can be used both to display and update external data.&lt;br /&gt;
&lt;br /&gt;
Have you ever wondered how to manage those data source connection settings across multiple SharePoint 2010 farms? How do you change the SQL Server name and other login information when deploying to your test and staging farm, and then to your production farm without using SPD again? Even good BCS books such as &lt;a href="http://www.amazon.com/Professional-Business-Connectivity-SharePoint-Programmer/dp/047061790X"&gt;Professional Business Connectivity Services in SharePoint 2010&lt;/a&gt; have very little coverage of BCS external system settings in Central Admin and of how to actually use BDC resource files. There is a nice end-to-end overview in the &lt;a href="http://msdn.microsoft.com/en-us/library/gg650431.aspx"&gt;Migrating Business Connectivity Services External Content Types in SharePoint 2010&lt;/a&gt; article on MSDN, also lacking some of these details.&lt;br /&gt;
&lt;br /&gt;
Data source connection settings are stored as External System properties that can be configured from Central Admin by managing the BDC service application. This can be a bit confusing, as you might run into the "there are no configurable properties" message when trying to manage Settings for an External System. The trick is to remember that these settings are not for the external system per se, but for a specific external system instance aka connection. Chose the External Systems view in the ribbon, click the link of the applicable external system to see the instances, then select the instance and finally click Settings in the ribbon. Change the connection properties and click OK.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-kXTfjkI7I9s/Tblr4xZhBxI/AAAAAAAAAVk/-cB3Otc4Tuk/s1600/BCS_external_system_instance_settings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="191" src="http://3.bp.blogspot.com/-kXTfjkI7I9s/Tblr4xZhBxI/AAAAAAAAAVk/-cB3Otc4Tuk/s400/BCS_external_system_instance_settings.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
In the example data connection I've used the Secure Store Service (SSS) application for the login information because the target database requires SQL Server authentication instead of passthrough integrated Windows authentication.&lt;br /&gt;
&lt;br /&gt;
Instead of manually changing these External System settings whenever deploying a new version across your development, testing, staging and production farms, you can use &lt;a href="http://msdn.microsoft.com/library/aa674515.aspx"&gt;BDC resource files&lt;/a&gt; to apply the settings. This is done by exporting and importing resource files, either using Central Admin, code or Powershell.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-vguHu0NEfzA/TblyH12vKZI/AAAAAAAAAVo/If64EuH6RYM/s1600/BCS_export_import_settings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="161" src="http://3.bp.blogspot.com/-vguHu0NEfzA/TblyH12vKZI/AAAAAAAAAVo/If64EuH6RYM/s400/BCS_export_import_settings.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Prototype and test your BCS solution on your development farm first, then package your solution into a feature as explained in &lt;a href="http://msdn.microsoft.com/en-us/library/ff798309.aspx"&gt;How to: Deploy a Declarative BDC Model with a Feature&lt;/a&gt; on MSDN.  Remember to change the model name and external system name, including the  entity namespace into durable names, or at least change the entity  version, from your SPD prototype when packing your BDC model.&lt;br /&gt;
&lt;br /&gt;
The declarative BDC model is really just some XML stored in a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BDCM &lt;/span&gt;file. In addition to the BDC model file, SharePoint 2010 also supports  using &lt;a href="http://msdn.microsoft.com/library/aa674515.aspx"&gt;BDC resource files&lt;/a&gt; for specific metadata elements that commonly  change, such as SQL Server connection configuration. A resource file is really just some XML stored in a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BDCR &lt;/span&gt;file, that can be merged with the stored model without deleting the existing model and its configuration from the BCS metadata store.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-L7sbXhKXD78/TblzySV_pEI/AAAAAAAAAVs/8ApxL_Aysbg/s1600/BCS_resource_file.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="261" src="http://3.bp.blogspot.com/-L7sbXhKXD78/TblzySV_pEI/AAAAAAAAAVs/8ApxL_Aysbg/s400/BCS_resource_file.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The simplest way to get a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BDCR &lt;/span&gt;file to start with, is to export the BDC resources using Central Admin.  Chose the BDC Models view in the ribbon, then select the applicable model and finally click Export in the ribbon. Set the file type to Resource and select which resources to include in the exported &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BDCR &lt;/span&gt;file, typically properties, and click Export to save the selected set of resources.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ttgnwS_1Y0Y/TbpcNMn9VYI/AAAAAAAAAVw/K6bW4gruV3g/s1600/BCS_export_resources.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="222" src="http://1.bp.blogspot.com/-ttgnwS_1Y0Y/TbpcNMn9VYI/AAAAAAAAAVw/K6bW4gruV3g/s400/BCS_export_resources.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Edit the the &lt;a href="http://msdn.microsoft.com/library/aa674515.aspx"&gt;resource XML&lt;/a&gt; to change e.g. the name of the SQL Server (RdbConnection Data Source) and save your changes, using one file per BDC model and target farm. Only the XML for settings that should be updated when applying the resource file need be in the file.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-IujFb1w7bk4/TbplqL74LaI/AAAAAAAAAV4/IcfQOBrcj7s/s1600/BCS_resource_file_edited.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="181" src="http://1.bp.blogspot.com/-IujFb1w7bk4/TbplqL74LaI/AAAAAAAAAV4/IcfQOBrcj7s/s400/BCS_resource_file_edited.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The edited BDC resource file can now be applied to the applicable BDC model in one of your farms, typically when deploying a new version of a model to the staging or production farm. Chose the BDC Models view in the ribbon, then select the applicable  model and finally click Import in the ribbon. Click Browse to select the applicable resource file and set the file type to  Resource. Then select which resources to import from &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BDCR &lt;/span&gt;file, typically properties, and click Import to load the selected set of resources.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-kh-Xkwiy2nQ/TbphWskOMmI/AAAAAAAAAV0/_gBLXNDY1es/s1600/BCS_import_resource_file.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="257" src="http://2.bp.blogspot.com/-kh-Xkwiy2nQ/TbphWskOMmI/AAAAAAAAAV0/_gBLXNDY1es/s400/BCS_import_resource_file.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Validate that the correct settings were imported by reviewing the import log warnings, and by reviewing e.g. the settings for your external system instance or the permissions for the BDC model and its external content types.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-pZNQrnz6ZHU/Tbpl9i2WmbI/AAAAAAAAAV8/5CMH4gWS_Ac/s1600/BCS_imported_resource_file.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="156" src="http://3.bp.blogspot.com/-pZNQrnz6ZHU/Tbpl9i2WmbI/AAAAAAAAAV8/5CMH4gWS_Ac/s400/BCS_imported_resource_file.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
See &lt;a href="http://msdn.microsoft.com/en-us/library/ee231564.aspx"&gt;How to: Use a Resource File to Specify Localized Names, Properties, and Permissions&lt;/a&gt; on MSDN to include an edited BDC resource file in a feature in your Visual Studio 2010 package. Note that BDC models created with SPD cannot be exported from CA as they are not complete. Such declarative BDC models must be exported from SPD.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-3723730767773055960?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/-GW0i3mPO30" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/3723730767773055960/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=3723730767773055960" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3723730767773055960?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/3723730767773055960?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/-GW0i3mPO30/bcs-resource-files-data-source.html" title="Using SP2010 BCS Resource Files for BDC Model Settings" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-kXTfjkI7I9s/Tblr4xZhBxI/AAAAAAAAAVk/-cB3Otc4Tuk/s72-c/BCS_external_system_instance_settings.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/04/bcs-resource-files-data-source.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEICQXozfip7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-1878603767772168027</id><published>2011-04-28T09:24:00.006+02:00</published><updated>2012-02-16T21:02:40.486+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-16T21:02:40.486+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SqlServer" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="BCS" /><category scheme="http://www.blogger.com/atom/ns#" term="SearchDriven" /><title>Using Dynamic Stored Procedures in BCS Finders</title><content type="html">We use quite a lot of Business Connectivity Services (BCS) at my current SharePoint 2010 project both for traditional integration of data from external systems into web-parts and lists, and also for crawling external systems for integrating those system using search and search-driven web-parts.&lt;br /&gt;
&lt;br /&gt;
One of our integration partners prefers to provide their integration points as SQL Server 2008 stored procedures, which is very well supported by BCS. BCS supports both stored procedures and table valued functions, called "routines" in SharePoint Designer (SPD). SharePoint Designer is dependent on being able to extract metadata about the returned table data set when adding External Content Type (ECT) operations or when using the Operations Design View.&lt;br /&gt;
&lt;br /&gt;
Alas, the provided integration sprocs used dynamic SQL statements, and for technical reasons this could not be rewritten to inline SQL select statements. This is as always a problem with tooling such as SPD, as no result set metadata can be discovered. When connecting SPD to the external system, I got no fields in the Data  Source Elements panel in the Read List operation's Return Parameter  Configuration. Rather I got three errors and a warning.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-iiSyyEHJssM/TbkQyiUnSLI/AAAAAAAAAVc/4PX88KohhC4/s1600/BCS_untyped_resultset.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="145" src="http://2.bp.blogspot.com/-iiSyyEHJssM/TbkQyiUnSLI/AAAAAAAAAVc/4PX88KohhC4/s400/BCS_untyped_resultset.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The workaround is quite simple and requires the use of a SQL Server table variable, which defines the result set and allows SPD to discover the table metadata. Rewrite the stored procedure by declaring a table variable, insert the result of the dynamic SQL statement into the variable, and finally return the result set by reading the table variable. The changes to the sproc is shown in blue in this example:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [dbo].[GetFavorites]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;AS&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @DbName &lt;span class="kwrd"&gt;AS&lt;/span&gt; NVARCHAR(&lt;span class="kwrd"&gt;max&lt;/span&gt;) = &lt;span class="str"&gt;'ARISModellering1'&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @ObjDef &lt;span class="kwrd"&gt;AS&lt;/span&gt; NVARCHAR(&lt;span class="kwrd"&gt;max&lt;/span&gt;) = dbo.GetArisTableName(@DbName, &lt;span class="str"&gt;'ObjDef'&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @Model &lt;span class="kwrd"&gt;AS&lt;/span&gt; NVARCHAR(&lt;span class="kwrd"&gt;max&lt;/span&gt;) = dbo.GetArisTableName(@DbName, &lt;span class="str"&gt;'Model'&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @FavoriteSQL &lt;span class="kwrd"&gt;AS&lt;/span&gt; NVARCHAR(&lt;span class="kwrd"&gt;max&lt;/span&gt;) = N&lt;span class="str"&gt;'&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;SELECT&lt;/pre&gt;
&lt;pre&gt;ARISBPDATA.BOOKMARKS.ID AS FavoriteId&lt;/pre&gt;
&lt;pre class="alt"&gt;, ARISBPDATA.BOOKMARKS.DESCRIPTION AS FavoriteName&lt;/pre&gt;
&lt;pre&gt;, ModelType.ModelTypeName AS FavoriteType&lt;/pre&gt;
&lt;pre class="alt"&gt;, LOWER(ARISBPDATA.BOOKMARKS.USERNAME) AS UserName&lt;/pre&gt;
&lt;pre&gt;, '&lt;span class="str"&gt;'http://puzzlepart/index.jsp?ExportName=ARISModellering&amp;amp;modelGUID='&lt;/span&gt;&lt;span class="str"&gt;'&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="str"&gt;+ ARISBPDATA.BOOKMARKS.DATAKEY AS FavoriteUrl&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;FROM&lt;/pre&gt;
&lt;pre&gt;ARISBPDATA.BOOKMARKS&lt;/pre&gt;
&lt;pre class="alt"&gt;INNER JOIN ' + @Model + &lt;span class="str"&gt;' m ON ARISBPDATA.BOOKMARKS.OBJID = m.Id&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;INNER JOIN ModelType ON m.TypeNum = ModelType.ModelTypeId&lt;/pre&gt;
&lt;pre class="alt"&gt;'&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @userFavs &lt;span class="kwrd"&gt;TABLE&lt;/span&gt;(FavoriteId &lt;span class="kwrd"&gt;int&lt;/span&gt; &lt;span class="kwrd"&gt;not&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;, FavoriteName nvarchar(&lt;span class="kwrd"&gt;max&lt;/span&gt;),&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;FavoriteType nvarchar(&lt;span class="kwrd"&gt;max&lt;/span&gt;), UserName nvarchar(&lt;span class="kwrd"&gt;max&lt;/span&gt;), FavoriteUrl nvarchar(&lt;span class="kwrd"&gt;max&lt;/span&gt;))&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;insert&lt;/span&gt; @userFavs &lt;span class="kwrd"&gt;EXEC&lt;/span&gt; sp_executeSQL @FavoriteSQL&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; * &lt;span class="kwrd"&gt;from&lt;/span&gt; @userFavs&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;END&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Refreshing the external system data connection and then creating the ECT read list operation now works fine, and all the return type errors and warnings are gone.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-dFZwNbPkp7k/TbkWHJ0VE0I/AAAAAAAAAVg/IYzj4tMvFXE/s1600/BCS_typed_resultset.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="215" src="http://2.bp.blogspot.com/-dFZwNbPkp7k/TbkWHJ0VE0I/AAAAAAAAAVg/IYzj4tMvFXE/s400/BCS_typed_resultset.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Note that the classic #temp table workaround won't work with SPD, you have to use a table variable in your stored procedure. The sproc will now use more memory, so the BCS best practice for keeping finder result sets small applies.&lt;br /&gt;
&lt;br /&gt;
The table_variable declaration is also a good place to make sure that the identifier column is "not null" and that it is a supported BCS data type such as "int32". External lists cannot be created from an ECT whose identifier field is unsupported, such as SQL Server "bigint", and I strongly recommend using a supported identifier data type right from the start. Getting the ECT identifier wrong in the BCS model will give you problems later on when using SharePoint Designer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-1878603767772168027?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/qoEw9C6NkQI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/1878603767772168027/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=1878603767772168027" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/1878603767772168027?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/1878603767772168027?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/qoEw9C6NkQI/stored-procedures-in-bcs-sharepoint.html" title="Using Dynamic Stored Procedures in BCS Finders" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-iiSyyEHJssM/TbkQyiUnSLI/AAAAAAAAAVc/4PX88KohhC4/s72-c/BCS_untyped_resultset.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/04/stored-procedures-in-bcs-sharepoint.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4MRn0yeyp7ImA9WhZXEEU.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-7937137525653552822</id><published>2011-04-20T15:09:00.000+02:00</published><updated>2011-04-29T16:23:07.393+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-29T16:23:07.393+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="BCS" /><title>BCS External Lists causes SharePoint 0x80131600 exception for SPSiteDataQuery</title><content type="html">Issue: Your SharePoint 2010 code use the SPSiteDataQuery or CrossListQuery and get an exception with code &amp;lt;nativehr&amp;gt; 0x80131600 and absolutely no other helpful details.&lt;br /&gt;
&lt;br /&gt;
Cause: External list referencing an external content type that has been deleted from the BDC metadata store.&lt;br /&gt;
&lt;br /&gt;
Solution: Delete the applicable external lists from your sites - or recover the deleted external content type.&lt;br /&gt;
&lt;br /&gt;
A related error code is code 0x8102003 which is caused by missing list definitions in activated features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-7937137525653552822?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/xCGFiqjMJGo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/7937137525653552822/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=7937137525653552822" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7937137525653552822?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7937137525653552822?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/xCGFiqjMJGo/sharepoint-0x80131600-spsitedataquery.html" title="BCS External Lists causes SharePoint 0x80131600 exception for SPSiteDataQuery" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/04/sharepoint-0x80131600-spsitedataquery.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8DRHk4eCp7ImA9WhZSFkk.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-7686732208977028312</id><published>2011-04-01T09:34:00.006+02:00</published><updated>2011-04-01T10:01:15.730+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-01T10:01:15.730+02:00</app:edited><title>Installing SharePoint SPSF on Visual Studio 2010 SP1</title><content type="html">In preparing for the 2011 &lt;a href="http://www.arcticsharepointchallenge.com/"&gt;Arctic SharePoint Challenge&lt;/a&gt; next week with my awesome &lt;a href="http://www.puzzlepart.com/"&gt;Puzzlepart&lt;/a&gt; team, we're installing the &lt;a href="http://spsf.codeplex.com/"&gt;SharePoint Software Factory&lt;/a&gt; (SPSF) tooling available at CodePlex. There is a nice prerequisite installer that helps you download and install the Guidance Automation Extensions and Toolkit, but it would not install the guidance packages properly on my Visual Studio 2010 SP1.&lt;br /&gt;
&lt;br /&gt;
Installing GAT2010.vsix failed with missing "Visual Studio 2010 SDK", so I downloaded that and got the "you must have Visual Studio 2010 installed" error instead. As it turns out, you will of course need "Visual Studio 2010 SP1 SDK" (&lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=21307C23-F0FF-4EF2-A0A4-DCA54DDB1E21"&gt;download&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-oagAJ859Y9c/TZV_emwropI/AAAAAAAAAVU/UkubkSm-mmM/s1600/SharePoint+SPSF+in+Visual+Studio+2010+SP1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="205" src="http://3.bp.blogspot.com/-oagAJ859Y9c/TZV_emwropI/AAAAAAAAAVU/UkubkSm-mmM/s400/SharePoint+SPSF+in+Visual+Studio+2010+SP1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Now I've got the SPSF project types in the Guidance Packages section of File &amp;gt; New Project and are ready for &lt;a href="http://twitter.com/#%21/search/%23asc2011"&gt;#ASC2011&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-7686732208977028312?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/wL9bGtCG0Es" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/7686732208977028312/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=7686732208977028312" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7686732208977028312?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/7686732208977028312?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/wL9bGtCG0Es/installing-sharepoint-software-factory.html" title="Installing SharePoint SPSF on Visual Studio 2010 SP1" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-oagAJ859Y9c/TZV_emwropI/AAAAAAAAAVU/UkubkSm-mmM/s72-c/SharePoint+SPSF+in+Visual+Studio+2010+SP1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/04/installing-sharepoint-software-factory.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEAFSXc9cCp7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-916229522132188136</id><published>2011-03-15T15:28:00.006+01:00</published><updated>2012-02-16T21:05:18.968+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-16T21:05:18.968+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ActivityFeed" /><category scheme="http://www.blogger.com/atom/ns#" term="WebPart" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="MySite" /><title>SharePoint News Feed Formatting of ActivityEvent</title><content type="html">It is quite easy the get the news feed for activities from your colleagues and for your interests and skills in SharePoint 2010. It is not, however, that simple to format each event to display them in your own web-part using the activity feed object model.&lt;br /&gt;
&lt;br /&gt;
Sure, the data of the different activity types are all there in the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ActivityEvent&lt;/span&gt; object, and you can get the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ActivityTemplate&lt;/span&gt; based on the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ActivityType&lt;/span&gt; of the event. But then you need to process the display template tags to merge in the event values or the event XML from &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;TemplateVariable&lt;/span&gt; string property using the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SimpleTemplateFormat&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ActivityTemplateVariable&lt;/span&gt; classes. See the &lt;a href="http://statto1974.wordpress.com/2011/03/14/fun-and-games-with-the-activityevent/"&gt;Fun and Games with the ActivityEvent&lt;/a&gt; post by Toby Statham to get you started.&lt;br /&gt;
&lt;br /&gt;
Luckily, the activity feed is based on the web syndication model, so you can simply create a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SyndicationItem&lt;/span&gt; object based on the activity event, and it will find and process the activity template for you:&lt;br /&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;br /&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; Panel CreateFeedEventPanel(ActivityEvent activity)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    Panel panel = &lt;span class="kwrd"&gt;new&lt;/span&gt; Panel()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;CssClass = &lt;span class="str"&gt;"MyProfileActivityFeedEventPanel"&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    };&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;//access the LinkList property in order to populate the ActivityEvent&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    List&amp;lt;Link&amp;gt; temp = activity.LinksList;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; picture = activity.Publisher.Picture;&lt;/pre&gt;
&lt;pre&gt;    picture = &lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(picture) ? &lt;span class="str"&gt;"/_layouts/images/O14_person_placeHolder_32.png"&lt;/span&gt; : picture;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;/pre&gt;
&lt;pre&gt;    Image publisherImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Image()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;ImageUrl = picture,&lt;/pre&gt;
&lt;pre class="alt"&gt;AlternateText = activity.Publisher.Name,&lt;/pre&gt;
&lt;pre&gt;CssClass = &lt;span class="str"&gt;"MyProfileActivityFeedEventPublisher"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    };&lt;/pre&gt;
&lt;pre&gt;    panel.Controls.Add(publisherImage);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    SyndicationItem syndicationItem = activity.CreateSyndicationItem(_activityManager.ActivityTypes, ContentType.Html);&lt;/pre&gt;
&lt;pre class="alt"&gt;    panel.Controls.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; LiteralControl() { Text = syndicationItem.Summary.Text });&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; panel;&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PopulateNewsFeedActivityList(&lt;span class="kwrd"&gt;bool&lt;/span&gt; useTodayOnly)&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; url = SPContext.Current.Site.Url;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SPSite site = &lt;span class="kwrd"&gt;new&lt;/span&gt; SPSite(url))&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;SPServiceContext context = SPServiceContext.GetContext(site);&lt;/pre&gt;
&lt;pre&gt;UserProfileManager profileManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; UserProfileManager(context);&lt;/pre&gt;
&lt;pre class="alt"&gt;SPUser user = SPContext.Current.Web.CurrentUser;&lt;/pre&gt;
&lt;pre&gt;UserProfile userProfile = profileManager.GetUserProfile(user.LoginName);&lt;/pre&gt;
&lt;pre class="alt"&gt;_activityManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; ActivityManager(userProfile, context);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (useTodayOnly)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    DateTime todayFilter = DateTime.Now.Date;&lt;/pre&gt;
&lt;pre&gt;    _activityList = _activityManager.GetActivitiesForMe(todayFilter);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    _activityList = _activityManager.GetActivitiesForMe(MaxItems);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The formatted HTML will be the same as rendered by the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NewsFeedWebPartBase&lt;/span&gt; class, except for the profile picture size and some missing timestamps for some event types. Use Reflector on the&amp;nbsp;news feed web-part&amp;nbsp;base&amp;nbsp;class to see the code for mitigating&amp;nbsp;such details.&lt;br /&gt;
&lt;br /&gt;
The code for &lt;a href="http://msdn.microsoft.com/en-us/library/ff426883.aspx"&gt;getting activity events for a user&lt;/a&gt; and other SharePoint 2010 social computing "how-tos" can be found&amp;nbsp;in the&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/ee557271.aspx"&gt;User Profiles and Social Data&lt;/a&gt; section at MSDN.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-916229522132188136?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/fFTrQUDZ0lk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/916229522132188136/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=916229522132188136" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/916229522132188136?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/916229522132188136?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/fFTrQUDZ0lk/sharepoint-news-feed-formatting-of.html" title="SharePoint News Feed Formatting of ActivityEvent" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/03/sharepoint-news-feed-formatting-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IDQ304fip7ImA9WhdVF0Q.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-4540995551706050805</id><published>2011-02-23T14:03:00.004+01:00</published><updated>2011-09-23T19:39:32.336+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-23T19:39:32.336+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration" /><title>Help Content Cannot Be Displayed in SharePoint 2010</title><content type="html">Today we had a weird error on our SharePoint 2010 production farm: clicking on help got the "help content cannot be displayed" error for all normal sites, even though it worked perfectly well in Central Admin. The same applied to Site Settings&amp;gt;Help Settings for the site-collection, it worked in Central Admin, but not in any other site. In addition, the 'SharePoint Foundation Search' service was running on one WFE server.&lt;br /&gt;
&lt;br /&gt;
First I checked all settings in &lt;a href="http://support.microsoft.com/kb/939313"&gt;KB939313&lt;/a&gt; without that fixing the problem, then I checked the log files and found this access denied error for our site's app-pool account:&lt;br /&gt;
&lt;br /&gt;
&lt;span lang="EN-US" style="font-family: Calibri, sans-serif; font-size: 11pt;"&gt;SqlError: 'The EXECUTE permission was denied on the object 'proc_EnumResourcesAtScope', database 'SharePoint_AdminContent_ABBAef34-7603-4da5-823a-43ee1327ABBA', schema 'dbo'.'&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Before embarking on changing any database rights, we decided to test with an English site just in case, as all our custom site definitions are in Norwegian. Lo and behold - help worked for the new team-site; and what's more, suddenly help was working for all our existing Norwegian LCID 1044 sites also. Go figure...&lt;br /&gt;
&lt;br /&gt;
[UPDATE] See the comments for tips on granting execute rights on the sprocs listed in the ULS to fix this problem once and for all - even beyond IISRESET.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-4540995551706050805?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/1iSCtC6xLpo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/4540995551706050805/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=4540995551706050805" title="11 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/4540995551706050805?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/4540995551706050805?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/1iSCtC6xLpo/help-content-cannot-be-displayed-in.html" title="Help Content Cannot Be Displayed in SharePoint 2010" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><thr:total>11</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/02/help-content-cannot-be-displayed-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUCQ346fip7ImA9WhZWGE8.&quot;"><id>tag:blogger.com,1999:blog-11096258.post-2253815964311158370</id><published>2011-02-21T10:28:00.005+01:00</published><updated>2011-05-19T17:51:02.016+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-19T17:51:02.016+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="Taxonomy" /><category scheme="http://www.blogger.com/atom/ns#" term="TermStore" /><category scheme="http://www.blogger.com/atom/ns#" term="ManagedMetadataService" /><title>Starting Term Store Management in SharePoint 2010</title><content type="html">If you can't get any edit or management popup menus such as add term store term group to show in the SharePoint 2010 Managed Metadata Service application Term Store Management Tool, check that:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Internet Explorer is started with "Run as administrator"&lt;/li&gt;
&lt;li&gt;You have added your taxonomy managers to the "Term Store Administrators" for the MMS root node&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-7C0miVvJ5YY/TWIwFtkT1oI/AAAAAAAAAVE/TiUpDgs2WLI/s1600/SP2010+Term+Store+Management.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="166" src="http://3.bp.blogspot.com/-7C0miVvJ5YY/TWIwFtkT1oI/AAAAAAAAAVE/TiUpDgs2WLI/s320/SP2010+Term+Store+Management.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
This is required even if you are an administrator of the MMS application itself and you have full control MMS connection permissions.&lt;br /&gt;
&lt;br /&gt;
So then&amp;nbsp;you're ready&amp;nbsp;to realize your ingenious &lt;a href="http://www.amazon.com/Organising-Knowledge-Taxonomies-Organisational-Effectiveness/dp/1843342286/"&gt;taxonomy for classifying and organizing your knowledge&lt;/a&gt; with managed metadata and content types.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11096258-2253815964311158370?l=kjellsj.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/InfoworkerSolutions/~4/yjrRbYk69wc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://kjellsj.blogspot.com/feeds/2253815964311158370/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=11096258&amp;postID=2253815964311158370" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/2253815964311158370?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/11096258/posts/default/2253815964311158370?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/InfoworkerSolutions/~3/yjrRbYk69wc/term-store-management-in-sharepoint.html" title="Starting Term Store Management in SharePoint 2010" /><author><name>Kjell-Sverre Jerijærvi</name><uri>http://www.blogger.com/profile/13654217591841196465</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="26" height="32" src="http://4.bp.blogspot.com/_VhGcD5-4xdY/SjEv-qMek4I/AAAAAAAAALQ/jid4lSvC95c/S220/kjellsj.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-7C0miVvJ5YY/TWIwFtkT1oI/AAAAAAAAAVE/TiUpDgs2WLI/s72-c/SP2010+Term+Store+Management.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://kjellsj.blogspot.com/2011/02/term-store-management-in-sharepoint.html</feedburner:origLink></entry></feed>

