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 profile sync details in this excellent article on the 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).
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:
And this is how my non-updated user information looks in my personal site:
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.
[UPDATE] A list of things to check, not all applies to SP2010 though: Troubleshooting User Profile Sync issues in Microsoft Office SharePoint Server 2007
As it turns out, all our personal sites get the "ProfileSynchronizationInternalException: ProfSynch: The site with ID <guid> 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 MSDN forum thread, which also provides an unsupported workaround that updates the Flags column of the Webs table in the My Site Host content database.
Thursday, September 08, 2011
Wednesday, August 10, 2011
Some Gotchas when Customizing the "My Content" Personal Site
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.
The MCS Norway team has done a good job of documenting the SharePoint element provisioning order, as part of their SiteConfigurator available at CodePlex:
I strongly recommend using or learning from the SiteConfigurator, download the feature and the source code from CodePlex and join the community there.
The MCS Norway team has done a good job of documenting the SharePoint element provisioning order, as part of their SiteConfigurator available at CodePlex:
"There are several steps in the creation process and SharePoint provisions in the following order:Here are some gotchas related to SPSPERS customization:
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."
- 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.
- 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.
- SPSite scoped stapled features, in quasi random order
- SPWeb scoped features defined in onet.xml, in the order they are defined in the file.
- SPWeb scoped stapled features, in quasi random order
- List instances defined in onet.xml
- Modules defined in onet.xml
- 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.
- The my content home page default.aspx do not exist yet during feature stapling; files and pages in onet.xml are provisioned in step 7.
- Do not create your own customized default.aspx file, it will get filled with the standard web-parts when the file's AllUsersWebParts are provisioned by the onet.xml module in step 7.
- 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
- 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.
- 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.
I strongly recommend using or learning from the SiteConfigurator, download the feature and the source code from CodePlex and join the community there.
Wednesday, July 06, 2011
Problem creating a FAST Content SSA in SharePoint 2010
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.
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. Make sure that both the SP2010 Administration and Timer services are running:
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 Deleteing the search service application and How to delete orphan configuration objects from SharePoint farm. 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".
Remember to configure SSL enabled communication 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.
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. Make sure that both the SP2010 Administration and Timer services are running:
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 Deleteing the search service application and How to delete orphan configuration objects from SharePoint farm. 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".
Remember to configure SSL enabled communication 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.
Labels:
Configuration,
FAST,
ServiceApplications,
SharePoint,
Topology
Friday, June 24, 2011
Delay Loading of Data in SharePoint 2010 Web Parts
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:
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 calling __doPostBack for each UpdatePanel from the page load 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.
A simple solution to this problem, is to put an asp:timer control inside the UpdatePanel 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.
Here are the code to two base classes that implements this delayed load approach:
The ApplyUserActions method is where you should fetch your data and update the content of the AjaxPanel member control. All the controls of your web-part should be created as usual, remember to call base.CreateChildControls in your derived web-parts to ensure that the Ajax controls get created.
Note that no slow data must be fetched and bound to your web-part controls during page load, e.g. in the CreateChildControls or OnPreRender methods, as this defeats the purpose of delay loading the data in the ApplyUserActions async postback method. A typical scenario is creating and configuring an SPGridView control in CreateChildControls and then fetch the data and set the grid's DataSource and call the grid's DataBind method in the overridden ApplyUserActions method in your derived web-part.
Note that all page event code get executed on partial postbacks 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 RebindControlsWhenNoViewState 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.
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 ASP.NET Ajax partial page updates. 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.
The more professional way of getting real asynchronous loading for web-part content is to use PageAsyncTask as shown in Chapter 9 in Wictor Wilen's excellent SharePoint 2010 Web Parts in Action 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.
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 calling __doPostBack for each UpdatePanel from the page load 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.
A simple solution to this problem, is to put an asp:timer control inside the UpdatePanel 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.
Here are the code to two base classes that implements this delayed load approach:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Puzzlepart.SharePoint.WebParts
{
public class AjaxPanelWebPart : System.Web.UI.WebControls.WebParts.WebPart
{
protected UpdatePanel AjaxPanel;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.EnsureChildControls();
}
protected override void CreateChildControls()
{
AjaxPanel = new UpdatePanel()
{
ID = this.ID + "UpdatePanel1",
UpdateMode = UpdatePanelUpdateMode.Conditional
};
Controls.Add(AjaxPanel);
UpdatePanelConfigurator.AddUpdatePanelProgress(AjaxPanel);
}
protected virtual void ApplyUserActions()
{
//to be overridden in derived classes
}
protected void RebindControlsWhenNoViewState()
{
if (Page.IsPostBack == true &&
System.Web.UI.ScriptManager.GetCurrent(Page).IsInAsyncPostBack == false)
{
ApplyUserActions();
}
}
}
public class AjaxPanelDelayedLoadWebPart : AjaxPanelWebPart
{
protected Timer LoadTimer;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.EnsureChildControls();
}
protected override void CreateChildControls()
{
base.CreateChildControls();
CreateLoadTimer();
}
private void CreateLoadTimer()
{
LoadTimer = new Timer()
{
ID = this.ID + "LoadTimer1",
Interval = 1 //millisecond
};
LoadTimer.Tick += new EventHandler<EventArgs>(LoadTimer_Tick);
AjaxPanel.ContentTemplateContainer.Controls.Add(LoadTimer);
}
protected void LoadTimer_Tick(object sender, EventArgs e)
{
LoadTimer.Enabled = false;
try
{
ApplyUserActions();
}
catch (Exception ex)
{
Label msg = new Label()
{
Text = "An error occurred in delayed load: " + ex.Message,
ToolTip = ex.ToString()
};
Controls.Add(msg);
}
}
}
}
The ApplyUserActions method is where you should fetch your data and update the content of the AjaxPanel member control. All the controls of your web-part should be created as usual, remember to call base.CreateChildControls in your derived web-parts to ensure that the Ajax controls get created.
Note that no slow data must be fetched and bound to your web-part controls during page load, e.g. in the CreateChildControls or OnPreRender methods, as this defeats the purpose of delay loading the data in the ApplyUserActions async postback method. A typical scenario is creating and configuring an SPGridView control in CreateChildControls and then fetch the data and set the grid's DataSource and call the grid's DataBind method in the overridden ApplyUserActions method in your derived web-part.
Note that all page event code get executed on partial postbacks 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 RebindControlsWhenNoViewState 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.
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 ASP.NET Ajax partial page updates. 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.
The more professional way of getting real asynchronous loading for web-part content is to use PageAsyncTask as shown in Chapter 9 in Wictor Wilen's excellent SharePoint 2010 Web Parts in Action 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.
Subscribe to:
Posts (Atom)



