Wednesday, March 17, 2010

Re-activating a feature with scope Web

Ever had a feature activated in several subsites, needing to be re-activated?

Uninstall / install feature will not work. But this command from Gary Lapointe will: gl-activatefeature (more information here).

It will perform the deactivate and activate in all subwebs, if you provide the command with the base site collection url. You can also define that only the webs with the feature already activated will have this re-activation done (using -ignorenoactive).

(Yet another) great command!

ErrorWebPart instead of SummaryLinkWebPart

I was working with some custom development where I needed to import some webpart from a top level page. This was done in 2 stages:

  1. it would start as the execution of a user button's action, i.e. the user would have a page to explicitly execute some code, including the webpart import.
  2. some event handlers would also trigger this same action, i.e. whenever someone checked in a pre-determined page.
In the first case, everything went fine. The webparts were successfully imported.

In the second case, the SummaryLinkWebPart would not be imported. Actually, the SPLimitedWebPartManager would not return a SummaryLinkWebPart, but a ErrorWebPart. It was a customized SummaryLinkWebPart, with a non-default MainXslLink, ItemXslLink and so on...

Apparently, the SPLimitedWebPartManager (or the SummaryLinkWebPart) need to have a request/context set in order to create/return the correct WebPart. Since in an Event Handler (or Timer Job) those objects are not created by default, it would return you that error object.

To make things worse, my code would return a "No parameterless constructor" exception on that ErrorWebPart, which got me in the wrong way to start with.

How to solve it? Just create the necessary objects, before getting the webparts from the SPLimitedWebPartManager:

HttpRequest request = new HttpRequest("", destinationWeb.Url, "");
HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter()));
HttpContext.Current.Items["HttpHandlerSPWeb"] = destinationWeb;

where destinationWeb is the web where the page you are importing webparts to is located (and perhaps it can actually be any web).

Don't know what really happens inside the Microsoft code to cause this behaviour, but I'm guessing it is some use of SPContext.Current to get a SharePoint object (like CurrentWeb).

Best SharePoint links

Highlighted content: STSADM/PowerShell Commands

(currently being edited with my favorite resources)

Friday, March 12, 2010

Stupid things in SharePoint 2007 API

For future reference:
  • ItemDeleted event receiver has no information whatsoever on the item that was deleted (quite useful then!)
  • SPWeb.GetFile(string) returns a SPFile object without the correct data (namely Exists and Length properties); using SPWeb.GetFileOrFolderObject(string) on the other hand, after instantiation, does return a valid and correct SPFile object
  • Also on the previous topic, you should always use the web where your file is! Using RootWeb may or may not work well (I have experienced this!). In my case, I was using RootWeb.GetFileOrFolder() / RootWeb.GetFile() and then file.OpenBinary() would return as exception of File Not Found. Using FileWeb.GetFileOrFolder() worked perfectly! As a confirmation of the strange behaviour, in an external console app, RootWeb.GetFileOrFolder() was working!
  • Event Handlers and Timer Jobs do not have request/context objects, that can sometimes be needed so that API methods work correctly and return what you expect (see this post)

(updated everytime I find "funny" things)

TechDays 2010 Lisbon, Road to SharePoint 2010, and more!

I will attend TechDays 2010 Lisbon, 20-22 April. I will try to attend every SharePoint session, and some Visual Studio ones too.

Another great initiative (that unfortunatelly I have not been attending), also for portuguese people, is Road to SharePoint 2010. Some good presentations already have their slides there. Not close to being in the presentation itself, but worth looking into.

There is also a great portuguese community site, Portuguese SharePoint Community, recommended to all portuguese SharePoint developers/architects out there!

Thursday, March 11, 2010

Google maps tips

Getting the current langitude and latitude of the map center while in Google Maps is always useful, just put in your browser's location url: javascript:void(prompt('',gApplication.getMap().getCenter()));

I have also been using clustering to show a set of gmarkers on the map, so that zooming in/out still gives us interesting information, instead of just a bunch of markers all over the place. The library we used was this one: http://googlegeodevelopers.blogspot.com/2009/04/markerclusterer-solution-to-too-many.html. Really good!

Enjoy.

Monday, March 8, 2010

SharePoint 2010 oficial release - May 12th

Microsoft has announced the official release of the new SharePoint version, in the Microsoft SharePoint Team Blog, in this post by Arpan Shah.

This should be a very interesting landmark.

I've been quite busy in a MOSS 2007 project, but I'm planning to get my hands on 2010 in the next few weeks and also attend TechDays 2010, here in Lisbon. From what I've seen, it seems like another huge step for SharePoint, both from the user point of view, but also (this time) for the developer too. Let's hope everything is as nice as it seems at first look.

I only saw some webcasts from Microsoft people, so I think that it might be in fact a great improvement for developers, but I'm guessing (like in 2007) there will still be many tricks to learn, not before some hours of pain. Let's pray for me to be wrong.

Monday, February 22, 2010

Anonymous access - login prompt

All SharePoint developers building WCM sites have probably run into this problem: anonymous access being prompted for login. Usually the SharePoint tools (namely Manage Content and Structure) should be enough to find the "offending" objects (with no published version), but sometimes they just tell you there are no drafts in the portal (although you do know there are).

The plausible reason I found for this is when you define specific permissions per web. Even if your user is site admin, apparently SharePoint does not crawl those webs searching for items matching that view.

The scenario where I got this behaviour was a multilingual site with several first level sites, each with specific permissions, since each one represented a company's unit, each with different editors.

Goggling it, I also found a page that provided me with a very useful way of finding them:
http://blog.thekid.me.uk/archive/2007/02/20/anonymous-sharepoint-publishing-site-forcing-login.aspx

Enjoy!

Monday, January 25, 2010

Performance optimizations

In the last days, I have been working on the final optimizations of a WCM site that will be released soon.

It's never late to remember two of the most important optimizations, in my opinion:

1. Assure that all images, CSS's, JS's and other static content have their cache definitions correct. The client browser should receive the information of the expire date correctly (and set to something like 365 days).

How to check this? Use Fiddler or Firebug (Net tab). If you refresh a page and still get requests sent to the server regarding static content (that receive 304 Not Modified replies) then you have a problem.

The more static content your page loads, the bigger the problem is, since your browser will check changes with the server for every file (therefore, 1 useless request per file).

This is probably the most important checkup you must do, since by default, for example, SharePoint will NOT cache the files in the Styles Library (known bug). Regarding this, I suggest you read a post by Chris O'Brien here.

2. Avoid loading SharePoint files in a fully customized frontend anonymous site

Anonymous users usually don't need the core.js/core.css/etc. These files are heavy and should be avoided

Webpart maintenance

If you are having trouble with some webparts or just want to perform some maintenance actions like closing or re-opening a webpart, you should check the webpart maintenance page, acessible everywhere by addint "?contents=1" to your page URL.

Can also be used for page layouts that have built-in webparts.