Folders with Meta-Data in SharePoint

When working with document libraries you can use folders to structure your documents within the library. This is ok, but a better approach to structure documents would be by assigning meta-data to the documents and create the structure based on this meta-data.

But sometimes you actually do need to have folders. For example you have bunch of documents which belong together. You could ZIP them up and thus have just one item in the document library, but this will stop you from being able to edit those documents directly in SharePoint. With SharePoint 2010 you could use document-sets, but what to do when you’re stuck with SharePoint 2007? Well, in this case you have to use folders.

OK, so folders it is. But how can I add meta-data to folders? When adding new columns to a library these will be available for all documents added to the library but not for folders. Here’s a trick to work around this problem:

  1. instead of added columns to the document library, create websitecolumns.
  2. create a new content-type, which derives from “document” to hold the actual documents of the document library. Add the websitecolumn created in step 1 to the content-type.
  3. create a new content, which derives from the type of “folder”. This content-type is being uses to create folders with meta-data in the document library. Add the websitecolmn of step 1 to the content-type.
  4. in the document library activate the use of content-types and deactivate the usage of folders(!), since we want to use our own content-type to create folders.
  5. add the in step 2 & 3 created content-types to the list and alter the order of the content-types in such a way the “document” type is not at position one. The first content-type of the list is always the default content-type and thus cannot be deleted. Once you alter the ordering you can delete the “document” content-type and just have your two custom content-types.

So now you can add folders to the document-library which also have meta-data. Interesting enough is the fact, that you can create a new content-type based on a content-type folder and then add this newly created content-type to the document library, but you cannot add the “raw” folder content-type to the library. However.

Active-Directory Groups in SharePoint

When adding an Active-Directory group to SharePoint, for SharePoint this group is like any other (user) account. SharePoint doesn’t care whether the account added is a group or just a single user. Because of this “ignorance” of SharePoint not the group-members are being added to SharePoint, but the AD-group. This group can then be used just like any other SharePoint user.

But there are a couple of caveats:

  • let’s take a task-list for example. When a task is being assigned to a person in a task list, this person will get an email notification of the task assignment. When a task is being assigned to a SharePoint group (not an AD-group!), then every member of the group gets the email notification. Also when looking at the task-list every group-member will see the task, as long as no group member has assigned the task to himself. Every group member can assign the task to himself, and by this the task will only show up in the users task-list, not anymore in the view of the other group members.
    When a task is being assigned to an AD-group no one receives an email, because SharePoint want’s to send an email to the groups email-address (since SharePoint doesn’t know that an AD-group is a group which consists of members, and hence it believes it’s a single user). And because SharePoint believes the AD-group is a single user the task can not be assigned to a member of the group – and also the task is not shown to the members of the group.
  • When assigning an AD-group individual permissions on a site I usually can send an email to the user notifying them about the new permissions. with AD-groups this doesn’t work as well, since usually AD-groups don’t have an email-address and SharePoint is unable to iterate over all the members of the AD-group. The same is true for setting up notifications for lists and libraries, these cannot be set to an AD-group.

Changelists in Subversion

I recently had a discussion on how to deal with configuration-settings, which might be different for every developer, in regard to subversion. The main question was: “should these files also be commited to the repository?”

The answer is plain and simple – yes! But it doesn’t make sense to check-in my settings for all other developers, and it even makes less sense that every developer is updating his settings every time he commits and thus overwriting the settings from the previous check-in.

Better: a standard-configuration file is being checked into the repository. This file could contain some placeholders, which must be individually updated. Every developer get’s this standard file on initial checkout, but all further updates to this file are being ignored by subversion.

This behavior could be achieved “manually” in such a way, that on check-in you just have to make sure, that you don’t commit the configuration file to the repository.

manuell_commit

This is obviously not really good. Most likely this will fail at some point in time and the individuall settings of a developer will get committed.

So we need a more sophisticated way to ignore certain files on commit. So there is the ignore-option of subversion, but that would also prevent us from initially checking in the standard-configuration. And maybe I would actually make a modification the the standard-configuration and update the file in the repository and make sure that every developrsconfiguration is being overwritten.

To achieve this subversion (or at least TortoiseSVN) offers a feature called change-list. To edit the change-list of a project you must open up the context-menu and “check for modifications”. In the context-menu of the shown files these can be assigned to a change-list. There is always on change-list already existend – “ignore-on-commit”.

ignore_liste1

An alternative is to start a commit and of all the file to commit these can also via the context-menu be assigned to a change-list.

After the configuration file has been assigned to the “ignore-on-commit” changelist, all updates to theses files will not be automatically commit (as the name might already imply).

commit

If the changes should however be commit, this can be done by simply checking the file in the commit dialog.

Presentation Font Cache is running wild

I just noticed, that my current workstation is actually working. Not that I would not appreciate the effort – but actually this is more than I expected.

So I have a Core2Duo running Windows 7 x64 Ultimate, and usually my CPU should be on an average of 10%. But recently this is up to 50%, one core is always running under full steam.

OK, so taking a look at the process explorer show, that the PresentationFontCache is actually causing all this. But why?

So someone on the MSDN Forums provided some help. First thing I noticed: I can’t stop the service, since it’s currently in startup-mode. And the service is also already set to manually startup.

Because I’m not an admin on my machine, I can’t just go to process-explorer and kill the task. Linux has this neet kill command, which Windows is missing.

OK, so I downloaded PsKill to do the job – but just to figure out, that a new process for the presentation-font-cache is spawning up. Oh-oh!

But I could delete the files, just as the forum-post suggested and this would actually stop the presentation-font-cache from restarting after another round of PsKill.

Errors that actually help to solve something

Well, suddenly it just happens – a YSOD. Just happened in my recent SharePoint dev-project.

Typical for SharePoint, this error is not obvious. Instead of the YSOD you’ll get a SharePoint specific page, telling you that something went wrong. No hint what happened or where the error actually occurred.

OK, so let’s head to the web.config and stop this hide-and-seek behaviors. I wanna know what’s happening. So we have to enable to show the actual CallStack and disable the use of CustomErrors.

<SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
<customeErrors mode="off">

OK, so now we’re talking. I have some sort of Null-Reference-Exception in my code. But this code just worked perfect on my dev-machine, so why is it failing on the test-machine? And why is something null anyway? The StackTrace tells me, that this happened in a property-getter.

private SPGridView _mySpGrid;
public void CreateChildControls()
{
    _mySpGrid = new SPGridView();
}
public bool HasRows
{
    get { return _mySpGrid.Rows.Count > 0; }
}

How can this be null? CreateChildControls is always being called, so the grid always exists. This cannot be the reason why.

OK, let’s try something totally irrational:

public bool HatWerte
{
    get { return _mySpGrid == null ? 0 : _mySpGrid.Rows.Count > 0; }
}

This could should actually not be necessary … except when this modification makes the Null-Reference-Exception to disappear. But just to make room for the next Exception. And now everything is making sense (and I could revert the above modification).

The next exception states:

Could not load file or assembly ‘System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’ or one of its dependencies. The system cannot find the file specified.

D’oh!

My application was build against .Net 3.5 and I didn’t install that on my test-machine. Since the test-machine is a Windows 2003 Server running SharePoint 2007 there was no need to install .Net 3.5 – yet!

But .Net could have told me so from the beginning on – I would have understood this. But instead it was hiding behind some Null-Reference-Exception, just like a coward!

Permission by obfuscation

… or how to hide certain actions in SharePoint?

There are a couple of things, which can not be configured in SharePoint. For example you cannot configure, that users are not able to edit a list in datasheet view or in Excel or Access. Bummer!

But with a couple of lines of JavaScript this isn’t really a challenge.

<script language="javascript" type="text/javascript" src="/Scripts/jquery-1.4.2.min.js"></script>
<script language="javascript" type="text/javascript">
$(document).ready(function() {
  $("[id$='_EditInGridButton']").remove();
  $("[id$='_ExportToSpreadsheet']").remove();
  $("[id$='_ExportToDatabase']").remove();
});
</script>

Just place this code in a Content-Editor-WebPart on the page and off you go!

The ultimate list of GUIDs

I’m not really sure, what is disturbing me more – the fact that I am actually searching for a GUID on Google, or the fact that there exists a list of GUIDs.

OK, so I have sharepoint manifest file, which is part of a site-template. This template has a whole lot of features, which have been added by sharepoint to the manifest and actually not needed at all. But all those features are only being described by their GUIDs – so who is who?

Lucky for me Robert Bogue has a blog-post, where he features a list of MOSS 2007 GUIDs. This was perfect to identify the features und to remove all the unwanted features from the manifest.

Configuring the Castle Windsor container

Just recently I stumbled across a code sample, which showed how to use the Registry-class of StructureMap to register classes to the container. Basically this looks like this:

public class RepositoryRegistry : Registry
{
    public RepositoryRegistry ()
    {
        For(typeof (IRepository<>)).Use(typeof (DummyRepository<>));
    }
}
container = new StructureMap.Container(x =>
{
    x.AddRegistry(new RepositoryRegistry());
});

So I though, this must also be possible in Castle Windsor – and indeed! So the equivalent in Castle Windsor would look like this:

using System;
using System.Reflection;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
public class RepositoryInstaller:IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(AllTypes
                               .Pick()
                               .FromAssembly(Assembly.GetExecutingAssembly())
                               .If(s => s.Name.EndsWith("Repository"))
                               .Configure(c => c.LifeStyle.Singleton));
    }
}
container = new WindsorContainer().Install(
    new NHibernateInstaller(sessionSource),
    new RepositoryInstaller(),
    new PresenterInstaller()
);

This is really cool, too bad I didn’t discover that before 🙂