Debugging SharePoint Custom Admin Pages

I think everyone knows about the <customErrors> tag in the web.config to enable error details to be displayed by the Runtime Error page, which you usually get when your aspx markup and related code-behind has a problem.
 
Normally this is set in the Virtual directory of the Web application along with another version of the web.config file in the Template/Layouts folder of the SharePoint HIVE.
 
But if you are developing Admin pages you need to set the RemoteOnly setting in the web.config that is found in the Template/Admin folder of the SharePoint HIVE.
 
 

Published: Oct-20-11 | 0 Comments | Link to this post

Accessing Location metadata using WIC - Windows Imaging Components

A customer just asked me how to retrieve the "City" metadata using the WIC. It's actually straight forward to pull that out of the IPTC information in most cases, as that is where Photoshop puts it when using the IPTC tab's "Sub-Location section, or the Origin tab.
 
app13/irb/8bimiptc/iptc/City
 
The "Country" is a little bit more tricky because the name of the resource contains a forward slash: ""Country/Primary Location Name"
 
/app13/irb/8bimiptc/iptc/Country\/Primary Location Name
 
Of course, one shouldn't confuse that "City" with the creator's "City" metadata,, which can be found here:
 
/xmp/CreatorContactInfo/CiAdrCity
 
HTH!

Published: Jan-22-11 | 0 Comments | Link to this post

SharePoint 2010 Translation "Gem"

We'll be releasing the FC.ImageSearch for SharePoint 2010 product also in German. While testing we recognized this very innovative translation of a list column name:
 
English: "CheckedOutUserId"
 
German: "ID des Benutzers, der das Element ausgecheckt hat"
 
Perfect down to the punctuation with the comma after "Benutzers". ROTFLMAO :-D
 
Hey, whoever translated that column name, you have a career opportunity: you should switch jobs and start writing books rather than technical documentation.

Published: Oct-27-10 | 0 Comments | Link to this post

More "Site Assets" issues

Haileselassi!
 
While we're finishing the port of our FC.ImageSearch product to SharePoint 2010 we're coming across a number of flaws with the search result mechanism and especially the "Site Assets" library, which is a new feature in the commercial version of SharePoint 2010.
 
What's wrong with this picture?
 
Site Assets search result data 
 
sitename
Well, the "Site Assets" part (marked in yellow in the screenshot above) is not a sub site but in fact the name of the library. So, the real sitename should be http://2k8r2x64sp10.
 
What's worse is that if you have a search result that is stored within a folder of a library then even the folder name will be concatenated to the sitename!
 
contentclass
As written in the previous blog post, the Site Assets library has a BaseTemplate and RegistrationID of "851". Well, that lack of better naming exists in the search result as well: while the Picture library has a proper contentclass of type "STS_ListItem_PictureLibrary", the Site Assets library is of contentclass "STS_ListItem_851".
 
picturethumbnailurl
Well, as you can see there are no thumbnails available for the images in a Site Assets library. Of course, that is wrong: as you probably noted, the Site Assets library absolutely contains the usual thumbnail and web preview images in the "_t" and "_w" folders. The links just don't get carried over to the search result.
 
 

Published: Oct-24-10 | 0 Comments | Link to this post

Site Assets library has RegistrationID 851

In case you haven't noticed: if you modify the Ribbon and think your modifications are fine by attaching to RegistrationID 101 (Document Library) then you won't have them show up for the Site Assets library, which has its own RegistrationID of 851.
 
I couldn't find the msdn entry for it. I am sure it's there as documentation is supposed to be sooo much better for SP 2010 (pun intended ;-)
 
Well, once I had the RegistrationID and did a search specifically for it I found 1 (ONE) page that had this info and also a comprehensive list for RegistrationID's: "Mike Smith's Tech Training Notes".
 
I love the SharePoint community! Otherwise half the solutions out there wouldn't exist.

Published: Oct-03-10 | 0 Comments | Link to this post

Crawled Properties not accessible from content application in SharePoint 2010

As we are in the process of porting our FC.ImageSearch product to SharePoint 2010 we came across a couple of Properties that are inaccessible if the code is running in the context of a Content Application, e.g. the AllCategories property of the schema object (more details on that here).
 
To make a long story short: Microsoft has opted to block access to certain data in the object model in order to prevent administration work to be done from a content application (instead of utilizing the central administration web application).
 
While I agree that security is always a concern I think that the current implementation is too tight.
 
One Example: In our scenario we want to give the site administrator the information which columns of the site's lists are mapped by which Managed Property's, so that he/she then knows how to configure the Advanced Search page properties accordingly. However, that's not possible as the CrawledProperty's - the "link" between columns and ManagedProperty's - are inaccessible from the content application.
 
Again, I consider it right to prevent any modifications to be made to the search' objects from a content application, but why cut off read access?
 
To solve this we implemented a custom WCF service on the central administration web application which the content application's code can talk to. While that's not bad or difficult it still doesn't feel right.
 
What do you think?

Published: Sep-20-10 | 0 Comments | Link to this post

Upgrade Your Windows SharePoint Services 3 installation to Search Server Express 2008!

Why? Because Microsoft Search Server Express (MSSX) is a great product, as it includes many of the search elements and the core search engine of the commercial MOSS 2007 product.
 
Upgrading from WSS3 to MSSX is actually not that difficult (really!). In fact, I usually install WSS as a farm first anyway and then upgrade the servers to MSSX as a second step.
 
If you haven't got anything installed yet, Windows Server 2008 R2 x64 is a great platform. Make sure you install SQL Server Express separately upfront, so you can choose the proper "advanced" installation for WSS3. Anything from SQL Server 2005 SP3 and up will do, but I also really like the brand-new SQL Server 2008 R2 Express.
 
The upgrade process is really nothing more than running the MSSX installer and the usual wizard afterwards, whereas you should install on the Central Admin server first and configure the MSSX-specific settings on that machine after the wizard has finished. The upgrade procedure is well described in this document.
 
Of course, there's a catch (it would be too easy otherwise, wouldn't it? ;-) After the upgrade is completed you might be missing some vital MSSX components, and if you're not familiar with MSSX you might not even know what you're missing.
 
Here's a couple of screenshots that point out the short-comings of the upgrade results:
 
Site Administration has no search settings links
 
What is wrong here is that the links to the search administration pages are missing.
 
Search Box with Scopes Dropdown missing
 
Well, not only are we missing the great "All Sites" scope for searching but even when adding a custom scope manually it simply won't show here.
 
One might be tempted to configure the "SmallSearchInputBox" but all attempts to do so are doomed. Both problems actually stem from the same problem and are simple to solve: the upgrade didn't automatically turn on the Web Application-level features for Search, as can be seen here:
 
Missing Web App Feature Activation
 
Once you've activated these features the SmallSearchInputBox will display properly (and can also be configured nicely under "\12\TEMPLATE\FEATURES\OSearchEnhancedFeature\SearchArea.xml" and voila, we now have a proper Search Box and even search configuration links in the Site Administration page are now showing:
 
Search configuration links partially available
 
Well, unfortunately there are still two links missing (for the "Search queries" page and the "Search results" page), so I've written a little feature to add those missing links as well (the pages for this functionality are actually installed, just the links are missing), which you can download here.
 
Enjoy the MSSX product. Once you've configured the search I am sure you will. And it doesn't get much better than free!

Published: May-10-10 | 0 Comments | Link to this post

SPFeatureReceiver.FeatureUninstalling ...or is it solution retraction?

I just realized there isn't that much documentation available on SharePoint's FeatureUninstalling method, so I thought I should share my experience with it.
 
FeatureUninstalling will only be called when the feature is uninstalled on the last web application. Therefore it is somewhat like a "Solution is being Retracted" event.
 
The properties.Feature property will be null, so you need to access your feature elements via the SPFarm object (SPContext doesn't work here either, as has been documented a lot on the web).
 
A solution retraction does NOT necessarily call a FeatureDeactivating for all deployed feature instances, so you might want to iterate through your WebApplications and Sites to clean up and deactivate any remaining features.
 

Published: Apr-29-10 | 0 Comments | Link to this post

ChangedProperties Property - Documentation Error

We're getting ready to ship the 2.0 version of our "Metadata Extractor" product that extracts metadata out of images and copies it into the list columns. One of the cool new features is that it also extracts the metadata when a new version of a file is uploaded (previously it only did that on the initial upload, which was hard enough, given the problems around the asynchronous ItemAdded eventhandler ...but that's another story ;-).
 
The best way to check what exactly has been changed on an item is to use the ItemUpdating and ItemUpdated events. However when we looked into storing information that was available in the ItemUpdating event that occurs first, so that we could access it in the ItemUpdated afterwards we were a bit confused about the documentation, especially the meaning and usage of the ChangedProperties property. MSDN states that it "gets properties that have changed". Well, not only is that as minimalistic as can be, but also simply wrong:
 
The ChangedProperties property can actually be used to store values from the ItemUpdating event to access them in the following ItemUpdated eventhandler.
 
Example:
If you add the following statement in your ItemUpdating eventhandler:
properties.AfterProperties.ChangedProperties.Add("FILEVERSION", item.File.Versions.Count.ToString());
...then you can access this value in the ItemUpdated eventhandler via:
string previousVersionNumber = properties.AfterProperties["FILEVERSION"].ToString();
Btw, if you step through your code you'll see that the key/value pair is actually being added to the ChangedProperties property. SharePoint then copies it over to the AfterProperties collection before the ItemUpdated eventhandler is invoked.
 

Published: Nov-15-09 | 1 Comment | Link to this post

Custom List Forms with Code-behind

There are a lot of articles on the web about manually modifying the list forms and the ListFormWebPart in particular, but there isn't that much information about modifying these forms programmatically, and the problems that come with that.
 
To start with, there's a great article on SharePoint List Forms by Hristo Pavlov that I highly recommend.
 
Customizing the ListFormWebPart is a chapter by itself, but what we needed was to customize the EditForm.aspx. Actually, we needed to inject a control that would prevent the form to come up while the asynchronous "ItemAdded" event, triggered by a file upload to the library, was still busy retrieving metadata (also an adventure in itself, as I consider that clearly a conceptual bug in SharePoint), which would result in an exception and a failure of the upload and/or the metadata extraction.
 
Now, there are actually two levels of forms one could utilize: each list/library has a set of these forms (New, Display, Edit) and the content types that are associated with the list/library also have these forms.
 
We chose to replace the EditForm.aspx of the document-type content types with a custom aspx form with code-behind. Why code-behind? Well, there are actually a couple of things one needs to adjust on the fly to make this work. One example would be that a custom application page should reside in the "_layouts/" space and the default.master masterpage that is used by the list forms is not directly accessible from there. But the most important reason was that the ListFormWebPart requires the "ListName" (it's actually the Guid ID of the list) and the "ListItemId" (which is what it sounds like :-) to be set properly when the OnInit event fires.
 
ListName&ListItemId
 
So, where's the problem? The ListFormWebPart is an incredibly flexible piece of programming art that can render itself on the fly automatically, depending on what list, content type and columns are to be displayed, BUT it does not retrieve the ListName and ListItemId from the Page.REQUEST automatically. Alright, we can do that with the code-behind, but that's NOT the problem ;-) The problem is that the control isn't available during the OnPreInit event to set these properties, and before the OnInit event handler gets fired SharePoint already throws an exception stating that no item could be found for the list and itemId specified ...Duhh!
 
Well, the solution is actually (as most things in life) trivial: the OnInit event fires on the controls before it fires for the page. Therefore it is important to add a code-behind event handler not only at the page level but also for the Web Part itself:
 
WebPart OnInit event handler registration
 
And the rather simple code-behind for this looks like this:
 
        protected void Lfwp_OnInit(object sender, EventArgs e)
        {
            string listId = Page.Request.QueryString["List"];
            string itemId = Page.Request.QueryString["ID"];

            ListFormWebPart lfwp = (ListFormWebPart)sender;
            lfwp.ListName = listId;
            lfwp.ListItemId = Convert.ToInt32(itemId);
        }

 
The beauty of this solution is that the same custom EditForm.aspx can then be used not only for all Picture Libraries, but also for Document Libraries.

Published: Oct-12-09 | 8 Comments | Link to this post
 Next >>