Ian Morrish recently posted a solution to the problem that _layouts/userdisp.aspx, the default destination of user links in SharePoint, won’t redirect to the user’s MySite in certain situations. His code works great, but there’s a bit of a snag: it breaks supportability. However, SharePoint’s delegate control functionality provides an opportunity to reproduce his results without breaking the rules. But first, we need to make a few tweaks to let his code work as a delegate.
Since the UserListForm property is protected (sigh), we need to find the control ourselves. FindControl doesn’t search down the control tree, so we need a method that does:
public static T FindControl<T>(this Control root, string id) where T : Control { Control c = root; Queue<Control> q = new Queue<Control>(); if (c == null || c.ID == id) return c as T; do { foreach (Control child in c.Controls) { if (child.ID == id) return child as T; if (child.HasControls()) q.Enqueue(child); } c = q.Dequeue(); } while (c != null); return null; }
This iterative implementation should perform better than its recursive alternative, particularly on a deep tree like that which SharePoint generates.
Next, we build our delegate control. Rather than reinvent the wheel, I used Zac Smith‘s example as a starting point:
public class ProfileMySiteRedirectControl : UserControl, IFormDelegateControlSource { public void OnFormInit(object objOfInterest) { Redirect(); } public void OnFormSave(object objOfInterest) { } protected void Redirect() { try { var s = Page.FindControl<FormComponent>("UserListForm"); var sc = ServerContext.Default; if (s == null || sc == null) return; var account = s.Item["Account"] as string; var mgr = new UserProfileManager(sc); if (mgr != null && mgr.UserExists(account)) Page.Response.Redirect(mgr.MySiteHostUrl + "/Person.aspx?accountname=" + account); } catch (SPException) { } } }
Finally, we need a feature to activate the control. Delegate controls are attached through features scoped at either the Farm or the WebApp level, with an element manifest containing something like this:
<Control Id="ProfileRedirection" Sequence="50" ControlAssembly="Solutionizing.ProfileMySiteRedirect, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f549a4d9093d696" ControlClass="Solutionizing.ProfileMySiteRedirect.ProfileMySiteRedirectControl" />
The ID matches the ControlID set on the delegate control in userdisp.aspx:
<SharePoint:DelegateControl runat="server" id="DelctlProfileRedirection" ControlId="ProfileRedirection" Scope="Farm" />
Because the delegate has Scope=”Farm”, our feature needs to be Farm-scoped as well.
Not as simple as Ian’s fix, but once it’s built you can reuse it anywhere with all the advantages of a solutionized customization.
Full solution on CodePlex:
Update 12/23/2008: New version: User Profile MySite Redirect 0.2
Update 3/27/2008: New version: User Profile MySite Redirect 0.3
December 11, 2008 at 9:03 pm
[…] User Profile MySite Redirect via Delegate Control […]
December 24, 2008 at 12:14 am
[…] December 24, 2008 — Keith Dahlby Per Ian’s suggestion, I’ve updated the MySite Redirect solution (CodePlex) to support the Force=True parameter passed by the “My Settings” […]
March 27, 2009 at 10:22 am
I have download the version 0.2, added solution and installed the feature but the My Settings link still points to the userinfomationlist on the site. Any step by step instruction is appreciated.
March 27, 2009 at 2:00 pm
If I’m understanding the question correctly, the My Settings link should stay at the user information list to allow editing. The redirect works on all other links to that user (from user fields, for example). If you do want to redirect away from the My Settings list, you can download the source and build your own version with the lines concerning
Request.QueryString["Force"]
commented out.March 28, 2009 at 6:39 am
Thanks for the quick response. This is what led me to your solution. We do not have Mysites enabled for our staff. We would like them to still have access to their My Profile page and click on Edit details to update their profile details successfully. Staff should not see their private Mysite but when they click on athe mysettings link to be directed to their Myprofile page. We are using MOSS2007 SP1 Only.
March 28, 2009 at 12:52 pm
Rather than redirect the My Settings link, I would add a separate link to My Profile. This could either be added to the Personal Action menu (where My Settings is) with a custom action, or as a replacement for the My Site link through the GlobalSiteLink1 delegate control. I may add these as additional features for this solution. Also, check out Ian’s post on the other details of using User Profiles without a MySite.
August 25, 2009 at 3:53 am
Keith, thanks for taking the time to write this up, I’ve found it helpful.
I am trying to get my head around the confusing world of Mysites/Profiles and the WSS simple user details page.
I follow everything you’ve said and also had previously looked at Zac Smith’s example. But I wonder if you can clear something up….?
You say above that “the My Settings link should stay at the user information list to allow editing.” – I don’t get this.
As I understood it, the WSS style user page doesn’t allow editing if you have a MOSS user profile, is that right? In this (my) case when you click “My Settings” from the Welcome control you get a pretty useless read-only page which won’t let you edit any of the fields…. So having the redirect to the mysite (with the edit details link) would be much more useful. I see how I can do this by removing the Force=True logic, but just wanted to check that my understanding is correct and that my environment is behaving as designed….. is it right that the user info page via “My Settings” isn’t editable in this case? If so, what did you mean above? Thanks for any help, appreciate it.
August 25, 2009 at 7:37 am
Andy ~
You are correct that with MOSS the profile fields are read-only. However, there are also two site-specific links on that page: My Regional Settings and My Alerts. Providing access to those is the purpose of the force parameter.
Alternatively, you could set My Settings to ignore Force and just provide those site collection preference links elsewhere, maybe in the Personal Action menu. However, going that route means that all documentation of the standard WSS/MOSS behavior will be useless to your users, so weigh accordingly.
Cheers ~
Keith
August 26, 2009 at 3:49 am
Ah, I see…. “Regional Settings” and “My Alerts” – that makes sense. I can see why you might need to go the page now. I’m happy that I understand what’s going on, thanks for clarifying.
Sorry – one supplemental Q – I’ve just checked and I can’t see a link for Regional Settings on userdisp.aspx – I just get “My Alerts” – any ideas?
Thanks again.
A.
June 23, 2009 at 12:41 am
[…] and GetDescendantControls June 23, 2009 — Keith Dahlby A while back I put together a quick and dirty implementation of a FindControl extension […]
March 12, 2010 at 4:17 pm
Should there be a userdisp.ascx in the codeplex source somewhere?
March 13, 2010 at 8:13 am
Perry ~
This solution builds on the existing userdisp.aspx – all you need is an assembly with the ProfileMySiteRedirectControl class (Solutionizing.ProfileMySiteRedirect.dll in my example), wired up through a Control element in a feature manifest.
Hope this helps ~
Keith
September 11, 2012 at 1:45 am
Actually there is no need to find the UserListForm control. You already have the SPListItem available from the OnFormInit method: just cast objOfInterest as an SPListItem and you are good to go :)
public void OnFormInit(object objOfInterest)
{
Redirect(objOfInterest as SPListItem);
}