Typical Web.config Tweaks

These are some web.config modifications that I typically need at my fingertips.  After all, who can memorize all this stuff?

Allow scripts to be embedded in asp pages.

      <PageParserPaths>
        <PageParserPath VirtualPath="/*" CompilationMode="Always" AllowServerSideScript="true" IncludeSubFolders="true" />
      </PageParserPaths>

Allow asp scripts to access external libraries

In the following case, SharePoint Taxonomy libraries:

<add assembly="Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

Create a reference to custom web service

Each method in the web service becomes a service “method”.

  <location path="_layouts/SPUtilities/SPservice.asmx">
    <system.web>
      <webServices>
        <protocols>
          <add name="HttpPost" />
        </protocols>
      </webServices>
    </system.web>
  </location>

Error reporting

Show a detailed error (rather than the generic sharepoint error).

Before:

<SafeMode MaxControls="200" CallStack="false" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">

After:

<SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="true">

Before:

<customErrors mode="On" />

After:

<customErrors mode="Off" />

Implementing Favorites in SharePoint 2010

As a SharePoint consultant, I’m often asked to provide features which “should” exist, but Microsoft just doesn’t provide. Often these are features which might be common in the Web 2.0 world, but – well, not here.

In one of my current projects (based on a Publishing Site), the paradigm of a “favorite button” is central to the desired site functionality. Users should be able to “favorite” any document or folder. These documents and folders are visible in a centrally located list, along with metadata items such as Modified Date and Author.

There are many possible ways to implement this, but initially I chose to use SharePoint 2010’s Social Tagging feature as the basic building block. It’s already set up to store link information by user, and integrates with the Keywords area of the Term Store. On the back end, this is the same mechanism used when you click “I like it” on any page.

This article is more concerned with the back end of things – the code listed below can be wrapped in web services, web parts or whatever you like, to provide functionality to the end user.

Tagging items

Social Tags are essentially key/value pairs, with the key being a Uri (e.g. the url of a web page), and the value being a description. In addition to the tag of “I like it”, other tags may be created in the Keywords area of the Term Store, and then used to tag documents. Here’s the code I’m using to tag a document:

 /// <summary>
/// Updates or adds a social tag for this user.
/// User info is derived from context.
/// Tag is added to term store if necessary.
/// </summary>
public static void UpdateSocialTag(SPSite site, string socialTagName, string title, string url)
{
            SPServiceContext context = SPServiceContext.GetContext(site);
            SocialTagManager mySocialTagManager = new SocialTagManager(context);
            //Retrieve the taxonomy session from the SocialTagManager.
            TaxonomySession taxSession = mySocialTagManager.TaxonomySession;
            TermStore termStore = taxSession.DefaultKeywordsTermStore;

            Term newTerm = termStore.FindOrCreateKeyword(socialTagName);
            Uri tagUri = ConvertToUri(site, url);
            mySocialTagManager.AddTag(tagUri, newTerm, title);
}

The reason this method is called “Update” is that if this Uri has already been tagged, that tag will be replaced.

Retrieving a list of favorites

I’ll also want to display my list of favorites. Social tagging does not intrinsically lend itself to pulling out the list of items which have a particular tag, but we can add that capability using the following code:

/// <summary>
/// Get the items tagged with TermName for this user.
/// If empty, return an empty array
/// </summary>
internal static SocialTag[] GetUserSocialTags(SPSite site, string termName)
{
    List<SocialTag> socialTags = new List<SocialTag>();

    SPServiceContext serviceContext = SPServiceContext.GetContext(site);
    UserProfileManager mngr = new UserProfileManager(serviceContext);  // load the UserProfileManager
    UserProfile currentProfile = mngr.GetUserProfile(false);// Get the user’s profile

    if (currentProfile == null) return socialTags.ToArray();            // user must have profile
    SocialTagManager smngr = new SocialTagManager(serviceContext);

    // Get the SocialTerm corresponding to this term.
    SocialTerm favTerm = GetSocialTerm(termName, currentProfile, smngr);
    if (favTerm == null) return socialTags.ToArray();

    // Get the terms for the user.  Loop through them for conformity.
    SocialTag[] tags = smngr.GetTags(currentProfile);
    foreach (SocialTag tag in tags)
        if (tag.Term == favTerm.Term)
            socialTags.Add(tag);
    return socialTags.ToArray();
}

/// <summary>
/// retrieve a named social term.
/// </summary>
private static SocialTerm GetSocialTerm(string tag, UserProfile currentProfile, SocialTagManager smngr)
{
    // Get the terms for the user
    SocialTerm[] terms = smngr.GetTerms(currentProfile);
    SocialTerm favTerm = null;

    //Iterate through the terms and search for the passed tag
    foreach (SocialTerm t in terms)
    {
        if (string.Compare(t.Term.Name, tag, true) == 0)
        {
            favTerm = t;
            break;
        }
    }
    return favTerm;
}

This code forms the “core” of my favorites system. The ability to tag a document (or remove tag) is wrapped in a web service to allow us to provide provide AJAX functionality. I wrote a web part to display the favorites, with simple sorting and filtering.

Metadata features

One missing element is the metadata, a part of the requirement I mentioned above. For this, I wrote code (as part of my Favorites Web Part) to pull out the necessary metadata for each Uri given, provided it’s a reference to the current site.

Building a SharePoint 2010 WSP Using TeamCity

I’ve been using Continuous Integration for years.  It’s been a part of almost every project I’ve worked on.  Prior to a few months ago, I was a CruiseControl.NET devotee, but recently a few of my colleagues expressed a preference for TeamCity.  I tried it, and now I’m a convert!

However, the Microsoft stack is not set up with CI in mind.  You’ll need to use a few tricks to set up your build on a computer which does not have a full dev environment.  This is particularly true when developing for SharePoint 2010 using Visual Studio 10.

Using TeamCity

Setting up TeamCity is pretty straightforward.  It’s a free product (up to 20 builds), and can be downloaded on the JetBrains web site.  I won’t go into the basics of TeamCity right now. However, once the product is installed, start by setting up a simple project with a version control settings, but no build steps – it simply downloads the code from your repository.

Preparing to use MSBuild

There are quite a few dependencies to satisfy, for a SharePoint build.  You’re using .NET 3.5, but you’ll want to make sure to use MSBuild 4.0 if you’ve been using VS2010. Features like WSP creation are not available in earlier versions.

Setting up dependencies

I used to do this step though trial and error, but recently found a great resource for this: http://msdn.microsoft.com/en-us/library/ff622991.aspx.  Follow the instructions in step 1. (Prepare the Build System).  Obviously we’re not using TFS here, so skip that step. This step outlines the dependencies, and instructs us on which dll’s we need to manually add to the GAC.  There’s a whole list.  The short explanation is that you copy the dll’s from your dev environment, and place them into the GAC the build server.

One “gotcha” here is that that you need to make sure you’re using the correct version of gacutil.exe when adding items to the GAC.  The reason is that .NET 4.0 adds a second GAC(!), so if you get the following message, you’ll know you have this problem:

Failure adding assembly to the cache:   This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.

On my machine, the path of the proper version of gacutil.exe was located in

C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\gacutil.exe

Make sure you are working from the most recent version of the Microsoft Windows SDK.   The following page should take you there: http://msdn.microsoft.com/en-us/windows/bb980924.aspx

Remember, YMMV here.  If you do not have SharePoint installed on your build machine, you’ll have to add any SharePoint dll’s necessary to build your project as well.  Anything that you miss will be readily apparent in the next step…

Adding your MSBuild step to TeamCity

Go back to the project you set up, and add a Build step.  Select MSBuild from the Dropdown. Your project should look similar to this:

image

Notice the Command Line Parameters setting.  IsPackaging=True causes the build to actually generate WSP’s for any of your projects that are configured to do so.  Without this parameter, a simple build will be performed.

Hope you enjoyed my first post!  Let me know how it goes.