Friday, August 22, 2014

Device channel panels and web part zones

I recently got the opportunity to create my first mobile device channel. The job seemed pretty straight forward. Create a new mobile master page and add device channel panels to the page layouts. The existing layout in a default panel and the mobile layout in a mobile panel. I instantly ran into a big problem. Device channel panels does not work with web part zones. The reason is that the web part manager knows which web parts should be displayed on a page and in which web part zone. If a web part is registered to a page but the web part zone is unavailable for some reason the web part manager will put that web part in the last available web part zone. This means that if you hide/display different web part zones with device channel panels you will get all web parts from the hidden web part zones in the last displayed web part zone. Well, isn't that just fantastic.

The only solution to this problem I have found is to use a rich text editor instead of a web part zone, but that isn't really the same thing.

Yet another day in SharePoint paradise...

Monday, May 5, 2014

Purge the recycle bin

I currently work in a project where we add and delete thousands of list items. My recycle bin had over 30.000 items and I had to clean it. Cleaning out that amount of items the standard way would take hours. I googled a bit and found out thet there is a hidden feature in the recycle bin. Go to the recycle bin page, type javascript:emptyItems(); in the address bar and hit enter. You will get a confirmation dialog and if you click yes the entire recycle bin will get purged! This works as well for recycle bins on individual sites and for the site collection recycle bin, on both SharePoint 2010 and 2013. Why Microsoft have decided to hide this gem is beyond me.

Yet another day in SharePoint paradise...

Tuesday, April 15, 2014

Enable e-mail functionality in task lists in SharePoint 2013

Recently I was set out to test if e-mail was properly configured in a SharePoint 2013 environment at a customer. Piece of cake, I thought. I created a task list and went to the advanced settings page to tick the "Send e-mail when ownership is assigned"-box. It was very hard since it simply wasn't there. Microsoft have removed the possibility to out of the box enable e-mail in task lists. Wonderful. Thankfully it is possible to enable this option with PowerShell, see http://bernado-nguyen-hoan.com/2013/04/26/enable-email-notifications-for-tasks-list-in-sharepoint-2013/. The property EnableAssignToEmail is available on the SPList object as well if you want to enable it with code.

Yet another day in SharePoint paradise...

Friday, April 4, 2014

SharePoint Server 2013 Service Pack 1 is now unavailable

Microsoft has done it again! The first service pack for the latest SharePoint version is flawed. For those who remember, the same mistake was done in June 2011 with SP1 for SharePoint 2010. According to Microsoft the current service pack for SharePoint 2013 will affect the ability to update installations in the future, see http://support.microsoft.com/kb/2817429/en-us:
"We have recently uncovered an issue with this Service Pack 1 package that may prevent customers who have Service Pack 1 from deploying future public or cumulative updates. As a precautionary measure, we have deactivated the download page until a new package is published."
Yet another day in SharePoint paradise...

Monday, February 3, 2014

Lookup field workaround

I have never really worked that much with lookup fields to connect lists before. Usually a choice field and/or a managed metadata field is enough. Now a customer requested a couple of lists that were connected to eachother. "No problem" was my initial response, but yet again SharePoint would take me on a journey down the road of frustration.

The customer needed one parent list and two child lists. The parent list should display the title field and some choice fields from the child lists. Sounds really simple. When I started creating the lists I quickly discovered that it is impossible to use choice fields as lookup fields. The workaround is both simple and brilliant, see http://bramnuyts.be/2011/04/05/using-a-lookup-field-on-a-choice-field-workaround/. Now it works just as the customer wanted, as long as you hide the calculated fields in the default view and the item display form.

Yet another day in SharePoint paradise...

Thursday, January 30, 2014

The evolution of SharePoint

After a year of working with SharePoint Online I reflected over what SharePoint have becomed. SharePoint is now a beast. It can almost do anything, except cure cancer. It is almost impossible to be expert of every aspect of the product any more. But new capabilities are not all a good thing. I'm worried that Microsoft have come to a point where the code base have become too much to handle. The fact that Microsoft itself cannot host the product properly any more fuel my thoughts. In my project we have had, in avarage, one severe hosting problem every week. This is not acceptable.

Even though you might be frustrated out of your mind sometimes when working with SharePoint you must always remember that you are not alone. I recalled this little gem on Stack Overflow. The guy is rather bitter, but he have some valid points. Read it and you will feel better! :)

Yet another day in SharePoint paradise...

Tuesday, October 1, 2013

The request uses too many resources

I currently work in a project where the solution is hosted in SharePoint Online and Azure. All communication between the web applications in Azure and SharePoint Online is done with the client object model. Before the summer vacation everything was working just fine. When we came back a couple of weeks later nothing worked. Our applications got a lot of "Ther request uses too many resources" responses from SharePoint Online. After getting past the first line support at Microsoft we eventually got to speak to someone who actually knew what they were talking about. We found out that Microsoft lowered the limit for operations in an execute query call during the summer without notifying anyone. The limit is controlled by the property ClientCallableSettings, see http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebapplication.clientcallablesettings.aspx. Since that kind of properties are untouchable in SharePoint Online we had to add several execute query calls on strategic places throughout our code.

Yet another day in SharePoint paradise...

Thursday, February 7, 2013

Thumbnail view does not work with jQuery

I started using the thumnail view on a site that I was building for a customer. All of a sudden my jQuery script stopped working, but just on the thumbnail view page. After some digging I found that the thumbnail view resets the meaning of $, which is essential in writing jQuery scripts. Thanks a lot Microsoft!

The solution is to wrap all your jQuery scripts with the following function definition:

(function ($) {

    // Your custom jQuery code

})(jQuery);

This will work for your own scripts, but if you have imported third party script libraries that does not wrap their code properly, they will fail.

Yet another day in SharePoint paradise...

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...