Thursday, September 29, 2011

SharePoint Timer Job stops at “Initialized” and clear SharePoint Cache

There are a lot of configuration items that SharePoint cache by default: features, solutions and timer jobs among many other stuff. According to Joe Rodgers in this entry, “The config cache is where we cache configuration information (stored in the config database) on each server in the farm. Caching the data on each server prevents us from having to make SQL calls to pull this information from the configuration database. Sometime this data can become corrupted and needs to be cleared out and rebuilt.”. Yeah.

So just imagine, what could happen if you deploy a solution with a custom timer job, and you forgot in the first line of code something like

System.Diagnostics.Debugger.Launch();


Boahhh: no trace, no error, no action, nothing.


Then you will probably need to clear the SharePoint configuration cache (like Joe Rodgers explain) or at least, if you know what is causing your problem, re-install the feature of your TimerJob. That will clear the cache for that feature/timerjob and when you upgrade your solution and install the feature again, SharePoint will cache the right one.

Tuesday, September 13, 2011

Check if a SharePoint user is member of an AD group

There are several ways to get this information:

But the easiest way I found was using the System.DirectoryServices.AccountManagement namespace. Incredible short implementation, best results… so something like this will solve the problem.


using System.DirectoryServices.AccountManagement;

protected bool CurrentUserIsMemberOfGroup(string groupName)
{
string userLogin = SPContext.Current.Web.CurrentUser.LoginName;
// To get the right context, run with elevated privileges
SPSecurity.RunWithElevatedPrivileges(delegate()
{
var principalContext = new PrincipalContext(ContextType.Domain);
var userPrincipal = UserPrincipal.FindByIdentity(principalContext, System.DirectoryServices.AccountManagement.IdentityType.SamAccountName, userLogin);
var group = GroupPrincipal.FindByIdentity(principalContext , groupName);
return userPrincipal.IsMemberOf(group);
});
}

Notice the SPSecurity.RunWithElevatedPrivileges, as it is necessary to get the info from our AD (in case it is not located in the same machine as our beloved SharePoint). Otherwise, you won’t get access to the “ContextType.Domain”.


Hope this helps somebody.


Cheers!

Sunday, September 4, 2011

Custom MySites TopLinkBar placed in a not-MySites site

It is hard to describe in only one line what I have been doing last week. Sorry about that, but I guess the problem is quite common between customers that want to integrate several different kind of SharePoint 2010 templates with the nice look & feel that MySites offers.

In short, I was asked to keep the same TopLinkBar from MySites in an intranet Team site and in a Basic Search Center site. They 3 were running obviously in 3 different web applications, and they should use the same links.

image

My first idea: add the control

<SharePoint:DelegateControl runat="server" ControlId="GlobalNavigation"/>

to the v4.master (for the TeamSite) and the minimal.master (for the SearchCenter) pages. Then just modify through the SiteSettings the Top Link Bar links in each of the Site Collections. The problem is that this kind of configuration is specifically for MySite based templates, and this will not work in any other type of templates. So although you can see now the TopLinkBar in your site, it is in fact a useless dummy bar that contains links to nowhere…


My second idea: create an own TopLinkBar, using a copy of the User Control TopNavBar.ascx located in CONTROLTEMPLATES which is the control rendered when you place the


<SharePoint:DelegateControl runat="server" ControlId="GlobalNavigation"/>

in the master pages. We can set this new control to our solution in a Module, adding this to the elements.xml


<Control Id="GlobalNavigation" Sequence="10" ControlSrc="~/_CONTROLTEMPLATES/CustomTemplates/CustomTopNavigation.ascx" />

Then, inherit from the class MySiteDataSource, which is being used to set the links in the navigation bar, and modify programmatically the navigation to set my own links. Here again there is a problem, which is the sentence in the MSDN article: This class and its members are reserved for internal use and are not intended to be used in your code. So no, I could not access these methods…


My third and final idea: it is pretty much the second one (create an own CustomTopNavigation.ascx control, add it to the master pages, blablabla) BUT, create my own SiteMapDataSource in my CustomTopNavigation control that I will set to the TopNavigationMenu itself in the DataSourceID parameter.


<SharePoint:AspMenu
     ID="MySiteTopNavigationMenu"
     Runat="server"
     EnableViewState="false"
     DataSourceID="MySiteTopNavDS"
     AccessKey="<%$Resources:wss,navigation_accesskey%>"
     UseSimpleRendering="true"
     UseSeparateCss="false"
     Orientation="Horizontal"
     StaticDisplayLevels="1"
     MaximumDynamicDisplayLevels="1"
     PopOutImageUrl=""
     SkipLinkText=""
     CssClass="s4-mysitetn">
  </SharePoint:AspMenu>
  <asp:SiteMapDataSource runat="server" id="MySiteTopNavDS"  SiteMapProvider="MySiteMapProvider" ShowStartingNode="false" />

Then, create somewhere in the code a custom SiteMap provider and set my links.


public class CustomNavigation : PortalSiteMapProvider
    {
        public override SiteMapNodeCollection GetChildNodes(System.Web.SiteMapNode node)
        {
            PortalSiteMapNode pNode = node as PortalSiteMapNode;
            if (pNode != null)
            {
                if (pNode.Type == NodeTypes.Area)
                {
                    SiteMapNodeCollection nodeColl = base.GetChildNodes(pNode);
                            SiteMapNode childNode = new SiteMapNode(…, "My Newsfeed");
                            SiteMapNode childNode1 = new SiteMapNode(..., "My Content");
                            SiteMapNode childNode2 = new SiteMapNode(…, "My Profile");
                            SiteMapNode childNode3 = new SiteMapNode(…, "New Link");
                            nodeColl.Add(childNode);
                            nodeColl.Add(childNode1);
                            nodeColl.Add(childNode2);
                            nodeColl.Add(childNode3);

                    return nodeColl;
                }
                else
                    return base.GetChildNodes(pNode);
            }
            else
                return new SiteMapNodeCollection();
        }
    }


And then, finally, modify in the web.config files of the web applications we want to change (not for MySites web application, obviously) the entry for the SiteMap provider. That means, replace


<add name="MySiteMapProvider" description="MySite provider that returns areas and based on the current user context" type="Microsoft.SharePoint.Portal.MySiteMapProvider, Microsoft.SharePoint.Portal, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

with


<add name="MySiteMapProvider" type="[namespace].CustomNavigation, […]" NavigationType="Global" /> 

I know it is not the cleanest way to modify this TopLinkBar, so if anyone has made it with another (and easier) method, I would really apprecciate this info Smiley.


Cheers!