Friday, December 21, 2012

RichTextField require RichImageField

Usually when you create page layouts you always have image fields on your page. Recently I created a page with just one RichTextField. The problem was that the RichTextField did not render properly. It rendered just as an ordinary FieldValue in a ms-formfieldvaluecontainer. After some extensive trial and error I found out that RichTextField required at least one RichImageField somewhere in the page layout to work properly. Apparently the RichImageField adds stuff that also is needed for RichTextField. So my solution was just to add a RichImageField for the PublishingRollupImage field, which is a field inherited from the Page content type that you never use anyway, in an empty div with display none and the RichTextField was working just fine.

<div style="display:none">
    <PublishingWebControls:RichImageField
        id="ImageFieldSharePointBugFix"
        FieldName="PublishingRollupImage"
        runat="server"/>
</div>

Yet another day in SharePoint paradise...

Friday, November 23, 2012

Overriding application pages

Previously when you wanted to override an application page you deployed your new application page to the Layouts folder, and created a http-module which redirected any requests for the old application page to the new one. This method still works in 2010, but now we also have the method UpdateMappedPage on the SPWebApplication object. This method creates a redirection without the use of a http-module. You simply define which application page you want to override and provide a new url. Sounds sweet, doesn't it? But keep your pants on. You define which application page you want to override with the enum SPCustomPage. This enum has the following values: None, AccessDenied, Confirmation, Error, Login, RequestAccess, Signout and WebDeleted. Thats it. This means that if you want to override any other application page you still have to create a http-module.

Yet another day in SharePoint paradise...

Thursday, October 18, 2012

Using SPWebConfigModification

Sometimes you need to add changes to web.config during SharePoint development. This is done by using SPWebConfigModification, see http://msdn.microsoft.com/en-us/library/bb861909.aspx. But there is one very big problem with the functionality of SPWebConfigModification, and that is the ApplyWebConfigModifications method.

If you use Microsoft's example in a feature receiver, which you probably would want to do, the method ApplyWebConfigModifications will, as the comment clearly describes, reapply all the configuration modifications each time it is called. Yes, ladies and gentlemen, lets read the sentence "Reapply all the configuration modifications" again. This means that if you have configuration modifications in different features and added one, all the other configuration modifications will be written once again to the web.config file. The method ApplyWebConfigModifications does not take in to account that the configuration modifications already exist in the web.config file.

The best solution I have found is not to use SPWebConfigModification at all. Manually changing your web.config files seems to be the best way.

If you still want to use SPWebConfigModification, do not try to be fancy and remove your configuration modifications because that does not work either. It is a bug in SharePoint 2010 and will never be fixed according to this thread http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/a77a3524-775c-4d04-9920-5bc831e5607a/.

Yet another day in SharePoint paradise...

Wednesday, September 19, 2012

Force an update of Web Analytics


With the service Web Analytics in SharePoint 2010 you can either see statistics reports in Central Administration or retreive information from it to display on your pages. There is one big drawback. The statistics are updated only once a day, and this cannot be changed anywhere in Central Administration. To check what the current settings of your Web Analytics service application, use the following Power Shell command:

PS> Get-SpWebAnalyticsServiceApplication -identity "web analytics service application"

By default the start time of the report consolidation is "Daily at 02:00". It is possible to change the time when the update is made with the following Power Shell command:

PS> Set-SpWebAnalyticsServiceApplication -identity "web analytics service application" -ReportConsolidationStartTime 12

This will change the start time of the report consolidation to "Daily at 12:00". Note that the number, 12 in my example, must be an integer value between 1 and 23. I haven't tried this myself yet, but this should mean that in theory you could write a Power Shell script, or something, that runs every half hour and pushes the start time forward one hour. This should force the report consolidation to run every hour instead of once each day. But to get up to one hour old statistics is usually not good enough, but it's the best you can do with the Web Analytics service. Too bad.

Yet another day in SharePoint paradise...

Profile import in 2010 cannot filter on AD-groups

The other day I was doing some configuring on a brand new SharePoint 2010 farm at a customer. My task was to configure the profile import just as their old SharePoint 2007 farm was configured. Easy peasy...not.

I started the user profile synchronization service, created a new connection to their AD, made the first synchronization and got no profiles at all. Then I remembered that the profile synchronization service account  must have replication directory changes permission. This sounds worse than it actually is and is fixed by following this TechNet article, http://technet.microsoft.com/en-us/library/hh296982.aspx#RDCdomain. After that the profile database was populated correctly.

Then I just had to create a filter for a handful of AD-groups. In SharePoint 2007 this was done by adding a LDAP-filter to the connection. In the filter you define what should be included/excluded in the synchronization. In SharePoint 2010 this is no longer a valid option. Instead you define one or more exclusion filters. First of all, to limit the filter to just being an exclusion filter is really stupid. The other setback is that it's not possible to filter on AD-groups any more, just AD-parameters! I found this official blog post to confirm this, http://blogs.msdn.com/b/spses/archive/2011/05/31/sharepoint-2010-profile-sync-inability-to-import-users-based-on-group-membership.aspx.

The story ends with a custom profile database clean-up job, which is a story in itself, and a slightly unhappy customer. I find some comfort in the fact that I'm not alone, http://donalconlon.wordpress.com/2011/04/26/fun-with-filters-user-profile-synchronization-somebody-shoot-me-now/.

Yet another day in SharePoint paradise...

WSS_UsageApplication proxy stopped

All of a sudden the web analytics reports on one of my development servers was not updating properly. I followed this http://technet.microsoft.com/en-us/library/ff453926.aspx but could not find anything wrong. Then I noticed that the service application proxy to the usage application was in status "Stopped". Since there is no way of restarting application proxies in Central Administration my first thought was to remove Web Analytics from the farm and recreate it again. Luckily I found this blog post before I started tearing things down, http://tristanwatkins.com/index.php/fixing-the-usage-and-health-data-collection-sa/. I ran the following Power Shell commands and after that the application proxy was in status "Started" again:

PS> $sap = Get-SPServiceApplicationProxy | where-object {$_.TypeName -eq “Usage and Health Data Collection Proxy”}
PS> $sap.Provision()

Yet another day in SharePoint paradise...

Tuesday, July 17, 2012

SharePoint 2013 is here!

Finally! During the spring we here in Sweden we got July 20 as the date for the beta release. Almost a month later it is here.

Download SharePoint Server 2013 preview: http://technet.microsoft.com/en-us/evalcenter/hh973397
Download SharePoint Foundation 2013 preview: http://www.microsoft.com/en-us/download/details.aspx?id=30345

It will take some time to download the files. In the meantime it is a good idea to have a look at the training videos.

SharePoint 2013 IT pro traning videos: http://technet.microsoft.com/en-US/sharepoint/fp123606
SharePoint 2013 Developer training videos: http://msdn.microsoft.com/en-US/sharepoint/fp123633

It will be interesting if to see I can run the server since the hardware requirements has shot through the roof, http://technet.microsoft.com/library/cc262485(office.15)?ocid=fwlink#hwforwebserver. I "only" have 16 GB RAM, which also is maximum. I'll probably have to ask my boss for a new computer.

Yet another day in SharePoint paradise...

Friday, July 13, 2012

Replace New Page menu item for publishing sites

Back in SharePoint 2007 when you created a new publishing page in a publishing site you got to a page where you had to enter a title and choose a page layout.


In 2010 you just get a pop-up where you enter the name of the new page.


The new page will get the "default" page layout. If you want to change the layout, which is true in a lot of cases, you have to do that in the ribbon menu after the page has been created. Thank you Microsoft, but this is not how anyone wants to work with their publishing pages. Thankfully there is hope. There is a page in the layouts-folder called CreatePage.aspx, which is the exact same page as in 2007!


So now you, of course, want to hide the old New Page menu item with a HideCustomAction element and add a new menu item with a CustomAction element which just points to CreatePage.aspx. Well... Unfortunately Microsoft has cut some corners implementing the three menu items you get when you enable the publishing feature, i.e. New Page, New Document Library and Manage Content and Structure. Instead of adding them as three independent custom actions they have created one custom action and added the menu items in code behind. This makes it impossible to hide one of the three since all are registered with the same Id.

The solution to this madness is to create a new custom action and change the action for the New Page menu item via the object model in the code behind.

Oh, and another thing. It is impossible to add the new custom action in the exact same spot as the old New Page menu item since Microsoft does not expose the property MenuGroupId in the custom action xml, http://msdn.microsoft.com/en-us/library/ms460194.aspx. So we have to add our new custom action in code behind.

Here is my CustomAction element:

  <CustomAction
    Id="SharePoint.Paradise.CustomActions.NewPage"
    Location="Microsoft.SharePoint.StandardMenu"
    GroupId="SiteActions"
    Rights="AddListItems"
    ControlAssembly="$SharePoint.Project.AssemblyFullName$"
    ControlClass="SharePoint.Paradise.CustomActions.NewPage">
  </CustomAction>

Here is the code behind for the custom action:

namespace SharePoint.Paradise.CustomActions
{
    public class NewPage : WebControl
    {
        // Hide the old "New page" menu item
        // Menu items for the publishing feature is not added properly so we can hide them in Elements.xml with HideCustomAction, thank you Microsoft
        protected override void OnPreRender(EventArgs e)
        {
            ToolBarMenuButton menu = ToolBarMenuButton.GetMenuControl(this);
            MenuItemTemplate item = menu.GetMenuItem("wsaCreatePage");
            if (item != null)
            {
                menu.MenuControl.HiddenMenuItems.Add(item);
            }
        }
        
        // Add a the new "New page" menu item
        // MenuGroupId in not exposed to Elements.xml so we can add "New page" in the same location as the old one, thank you Microsoft
        protected override void CreateChildControls()
        {
            MenuItemTemplate item = new MenuItemTemplate();
            item.Text = HttpContext.GetGlobalResourceObject("wss", "siteactions_createpage", CultureInfo.CurrentUICulture).ToString();
            item.Description = HttpContext.GetGlobalResourceObject("wss", "siteactions_createpagedesc", CultureInfo.CurrentUICulture).ToString();
            item.ImageUrl = SPContext.Current.Web.Url + "/_layouts/images/crtpage.gif";
            item.MenuGroupId = 200;
            item.Sequence = 100;
            item.ClientOnClickNavigateUrl = SPContext.Current.Web.Url + "/_layouts/CreatePage.aspx";

            this.Controls.Add(item);
        }
    }
}

Yet another day in SharePoint paradise...

Move a document into a document set

Document set is a new feature in SharePoint 2010. It is very neat to be able to group documents together with metadata, workflows, etc. Just one small thing. There is no way to move existing documents into document sets. I recently had to come up with a solution to this for a customer and I found this gem after some searching, http://gilleslauwers.wordpress.com/2011/05/31/move-a-file-to-a-document-set/.

I changed two things to make the solution perfect.

1. Added {SiteUrl} to options.url in Elements.xml to make it work for site collections with a managed path:

options.url = '{SiteUrl}/_layouts/Sam.MoveToDocumentSet/ChooseDocumentSet.aspx?ListId={ListId}&amp;ItemId={ItemId}';

2. Changed the CAML query to display all document sets, even those of custom content types:

query.Query = "<Where><Eq><FieldRef Name='FSObjType' /><Value Type='Lookup'>1</Value></Eq></Where>";

I would rather develop features that does something customer specific than do this, which should be included in the product.

Yet another day in SharePoint paradise...

True is false, but TRUE is true

I had the craziest idea the other day. What if I write "True" or "true" instead of "TRUE" for boolean properties that should be true in my Elements.xml. I have always written "TRUE" because that's what everyone does. I hadn't given it much thought before, so I just went bezerk and wrote "True".

To my biggest suprise the property became false.

It apperas that the only true true is TRUE. I would very much like to have a chat with the retard that wrote the parser for boolean properties in SharePoint.

Yet another day in SharePoint paradise...

Separator in CustomAction for EditControlBlock

I thought I was assigned the easiest of tasks: Add a separator between our custom action and the other menu items.

I had this custom action in the ECB-menu for documents that was working perfectly. All I had to do was to add a separator. How hard could it be? Well... Apparently Microsoft has left out the possibility to add separators in the custom action xml, http://msdn.microsoft.com/en-us/library/ms460194.aspx. The only possibility to add a separator is to create it code behind with a MenuSeparatorTemplate, http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.menuseparatortemplate.aspx. This would have been all fine and dandy if code behind was an option for ECB-menus, but it isn't allowed. You can only attach UrlAction to ECB-menus.

There is a solution where you can add a separator by changing core.js, http://weblogs.asp.net/jan/archive/2009/09/03/customizing-the-sharepoint-ecb-with-javascript-part-1.aspx, but this isn't a viable option for me. The only really doable solution I found was to add our custom action dead last in the ECB-menu by setting Sequence="2000" since the delete option apparently adds a separator after itself. I found this out just by coincidence.

Here is my CustomAction element:

  <CustomAction
    Id="SharePoint.Paradise.CustomAction.DoStuff"
    Location="EditControlBlock"
    Title="Do stuff"
    RegistrationType="ContentType"
    RegistrationId="0x0101"
    Sequence="2000">
    <UrlAction Url="javascript:alert('Hello World!');"/>
  </CustomAction>

This is how it turned out in SharePoint:



Yet another day in SharePoint paradise...