MOSS Development: Back to the Basics

July 21st, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

On October 6 and 7, the Software Development Network hosts the seventeenth SDN Conference in Noordwijkerhout in the Netherlands. During this two day conference several international speakers will share their knowledge about .NET, Information Worker, Usability, Architecture, DotNetNuke and many other topics.

During this conference I will present two sessions, "MOSS Development: Back to the Basics" and "Exploring the Architectural Boundaries of MOSS". Right now I'm working on the first one, and while gathering information I came across this very interesting list of Visual How Tos for SharePoint. Donald Hessing pointed this site out to me, which also has a lot of useful information and examples on how to start developing SharePoint solutions.

Combining the information on these two sites a .Net developer with no SharePoint knowledge can start building SharePoint solutions.
…And I've got more than enough inspiration to create a 75 minutes presentation!

Seven habits of highly effective bloggers

May 16th, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

 

I'm a fan of the book "Seven Habits of Highly Effective People" by Stephen Covey.

While I was searching for a related consultants training I came across this blog post from Alison Cameron about the seven habits of highly effective bloggers. Like the book it's nothing new or shocking, but still it's good to remember the obvious once in a while.

The "datenoyear" field in the SharePoint user profiles

May 13th, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

 

At the moment I'm working on the new and improved version of the Macaw Birthday web part.

This web part uses the Birthday field of the user profile to query for people who will have their birthday in the next "x" days. Where you can set "x" from the web part property pane. There's a bunch of other stuff that can be set from the pane, but that's not causing problems right now.

The SQL queries you can perform against the MOSS 2007 index do not only support negative date comparisons on complete dates. This looks like (from the SDK):
…WHERE LastModifiedTime <=DATEADD (DAY, -5, GETGMTDATE())

Which means that you can only compare against dates in the past, where I want to find dates from today till "x" days from now, and I want to disregard the year, which is also not possible.

This is my next problem. Even though the class is called datenoyear it stores a year with it when you save it. And when you use the search objects to retrieve the field it returns a year with that. In my case it always returns the year 2000. If I can be sure that this is the year that is always added to a datenoyear field that would help a lot because then I would no that I need to query for a date between today in 2000 till today +"x" in 2000. But I can't find any documentation on that.

Other possible approaches are the DataColumn Expressions and the DataView RowFilter, but that will only work if I know for sure that the year will always be 2000. In that case I can query for each day separately like:
DataView.RowFilter = "Birthday = #5/13/2000# OR Birthday = #5/14/2000# OR Birthday = #5/15/2000# OR Birthday = #5/16/2000#"
if "x" would have been four.

Right now I think I'm just going to filter when writing the HTML, which means that I have a DataTable with all user profiles present on the environment, instead of just the user profiles of the people who have their birthday in the next "x" days, but I'm out of inspiration right now. If anyone has another suggestion I would appreciate that..
Oh, and if anyone can tell me for sure that the year stored for datenoyear fields is 2000 than I would be grateful for that information as well…

Changing the language of an existing SharePoint site

April 29th, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

Recently we had a problem with a (pretty large) site. The problem was that the site was created in English, while it should have been created in Dutch.  All content was in Dutch of course, but for instance the Site Actions button still said Site Actions, and when adding a document the buttons were "New", "Upload" and "Actions".

In order to solve this a couple of possible solutions were explored:

  • Saving the site as template didn't work, because you can only see the saved site when you create a site in the original language of the site
  • Using backup and restore didn't work, the site kept it's original language
  • Changing the language through the object model didn't work, because the Language property of the SPWeb object is read-only

This last attempt did trigger me to think that the language of a site is stored at SPWeb level. It is also stored in the database in the Webs table. So I decided to do a little test with changing the language in de database. And it worked like a charm!

Now you need to know that you're not supposed to change data in the database and that doing so is not supported by Microsoft. For me this was a very simple solution though to a pretty big problem. And the best thing was that it only took me 30 seconds to write the query and about 0.02 seconds to run it. Everything in the site is now Dutch, except of course for already created lists and libraries. So the name of the Pages library is still Pages and does not change to Pagina's. But the Site Actions button calls itself Siteacties, the Master Pages are Hoofdpagina's and View All Site Content is called Alle site-inhoud weergeven. You get the picture.. ;-)  

For changing the language of all sites in the content database to Dutch the query would be:
UPDATE dbo.Webs SET Language = 1043

Changing the language of one site collection can be done with:
UPDATE dbo.Webs SET Language = 1043 WHERE SiteId = [[SiteCollectionId]]

And for changing the language of a single web or subsite you can use:
UPDATE dbo.Webs SET Language = 1043 WHERE Id = [[WebId]]

I'm tagged for the blogging Meme

April 11th, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

Bart Wessels was probably curious about whether I have a life next to SharePoint development, when he tagged me for Blogging Meme. It's a funny concept that let's bloggers share random stuff about themselves that you would otherwise never know about.
Although the original post said you need to come up with eight facts and eight other bloggers, I agree with Bart that five will do.

These are the  'Meme rules':

  • Each player starts with five random facts/habits about themselves.
  • People who are tagged need to write a post on their own blog (about their eight things) and post these rules.
  • At the end of your blog, you need to choose five people to get tagged and list their names.
  • Don’t forget to leave them a comment telling them they’re tagged, and to read your blog.

So here we go…five random facts about me:

  1. The first time I presented in public was at the SharePoint Conference in Berlin in 2007 with Bart Wessels for about 400 people
  2. I have a CBR 600 F and I love to ride it!
  3. The more sports the better, I play tennis, do rock climbing, running, bikram yoga and snowboarding.
  4. I love laying jigsaw puzzles
  5. My favourite event of the year (apart from vacations) is Lowlands

And the five lucky bloggers that I tag for meme are:

Serge van den Oever
Sander de Koning
Edwin Vriethoff
Teun Duynstee
Marianne van Wanrooij

Customizing the My Site look and feel

February 22nd, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

As a reaction to my post about adjusting the top level navigation on My Sites I got an email asking how you go about adjusting the look and feel of a My Site. Since I also touch upon that topic in a lot of my presentations I decided to write it down.

The problem with putting a design on My Sites is that you can't change the master page and the style sheet of your My Site through the user interface. This problem also occurs when you migrate a SharePoint 2003 environment with (a lot of) My Sites to SharePoint 2007. All these My Sites need to get the correct visual design and since all My Sites are site collections they can't inherit their master page and style sheets either.

I wanted to create a solution to this problem for both existing sites and new sites. I will use this blog post to describe the solution.


The basics

For both the deployment of a design on existing My Sites and the activation of a design on new My Sites a feature with the master page is needed. Also a style sheet needs to be deployed. The design feature looks like this:

The feature.xml file stores the metadata of the feature.

The scope of the feature is "Web"(=sub site) where you might expect "Site"(= site collection), the reason I chose web was that if you have a site with a lot of sub sites and you want to save one of the sub sites as a template and the sub site inherits it's master page from the site collection it resides under it occasionally won't save the correct design in the template.

There are two files that need to be deployed with this feature, the master page file and the element manifest file of the feature, design.xml. There is also a feature receiver for this feature that, on activation and deactivation will set the correct master page, style sheet and title graphic.

The element manifest file design.xml describes the inner workings of the feature. In this case the main purpose of the feature is to deploy the custom master page to the master page gallery.

The style sheet is deployed from a separate project that is used to deploy custom files to the MOSS 2007 12 directory (C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12). The structure of this project is the same as the structure of the 12 directory.

The featurereceiver will take care of assigning the correct master page and style sheet to each sub site the feature is activated on. If the feature is deactivated the default master page will be assigned again and no custom style sheet will be applied.

 


New sites

In order to activate the feature on all My Sites that are created from the moment you activate your feature on you can build a stapling feature. Feature stapling is a very cool thing in MOSS 2007 where you can build a separate feature to tie site definitions and features together.  Using feature stapling you can create an blank site (not based on the MOSS 2007 blank site!) and staple all functionality you want to that site definition. The features that are stapled to a site definition are activated when the site is created. Feature stapling can create n-to-n relations. One feature can be stapled to several site definitions and several features can be stapled to one site definition.

The stapling feature also has a feature.xml for it's metadata. The most prominent setting in the feature.xml is the fact that the feature is activated at the "Farm" scope. This means that it will work on all web applications within the farm. This is fine, since in most environments only one web application is used for My Sites and the feature is only stapled to the My Sites site definition as you can see in the element manifest file of the stapling feature, DesignStapling.xml. This ensures that on every site that is created with the My Site site definition the design feature is activated.

 

If you didn't want to create this functionality just for My Sites, but you would build it for all sites you could staple to the GLOBAL site definition. All other site definitions inherit from the GLOBAL site definition, so stapling the design feature to this will staple the design feature to almost all site types. A prominent exception on this is the blank site. In the site definition of the blank site it is defined that you can not staple anything to the blank site (AllowGlobalFeatureAssociations="False"). This is necessary, because SharePoint itself also staples features to the GLOBAL site definition and otherwise the blank site would not be blank.


Existing sites

Feature stapling will only have an effect on sites that are created after you stapled the feature to the site definition. This means that if you already have a lot of My Sites that you want the custom design activated on you need to think of something else.
For this purpose I created a simple console application that loops through all sub sites within a web application and that activates the feature on all of them. This feature can also be used to deploy changes in the master page to already existing sites.

The application application can both activate and deactivate the design on a specific web application. In order to start it you use on of the following options:

  • -o activatedesign -url [webapp url]
  • -o deactivatedesign -url [webapp url]

Depending on whether you entered the activating or deactivating operation the application will go to the activating or deactivating function. The code for both of them is displayed below.

 

Office SharePoint Server Search keeps results to itself

February 4th, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

Instead of some information I'm posting a question today..

We've build an application that uses the search functionality to roll up content. Only not all content gets returned in the way you would expect it to.

A description of the problem can be found here:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2789944&SiteID=1&mode=1

Any suggestions as to what's happening are greatly appreciated.

InTrack presentation about SharePoint deployment

January 9th, 2008 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

Today I gave Microsoft InTrack presentation about SharePoint deployment.

This was the agenda:

  • Content Deployment
  • Content Migration API
  • Site Definitions
  • Features
  • Feature Stapling
  • Solution Deployment
  • Forms Deployment

On forehand I thought that most people would probably already have tried to deploy either content or solutions, but that wasn't the case. It was clear that people still find it fuzzy what needs to be deployed and how this can best be achieved. I hope that I didn't only dazzle the attendants with the different types of deployment, but that the presentation also gave some clarity about the different deployment possibilities. I also hope that it will be easier for the attendants to start using solution deployment and that I was convincing enough that taking the time to set up a solution deployment will actually save you time when deploying your custom SharePoint solutions.

The slides can be found here.

Links on content deployment:
Content Migration Package Explorer
SharePoint Content Deployment Wizard
Beware of Import/Export
How to: Customize Deployment for Disconnected Scenarios
SharePoint Content Migration Object Model and Content Migration Packages

Link on Solution Deployment:
WSPBuilder
Creating a Solution

[update]
The presentation yesterday in the Microsoft Innovation Center in Barneveld was a lot of fun. There were more people that had already worked with SharePoint deployment.
I used a slightly adjusted set of slides that can be found here.

 

Lock down application pages on a public web site

December 27th, 2007 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

If you are creating public web sites and anonymous users have access to the site all anonymous users will have read access. By default this means that all users can also access the application and forms pages like for instance the allitems.aspx of the pages library. Now it's true that you would need to know the url to get there, but it still doesn't look very professional.

Microsoft felt the same way and has thought of a solution for this, the ViewFormPagesLockDown. Donald Hessing has written more about it on his brand new blog. Check it out!

Using SPWeb.EnsureUser(loginName) to add a new SPUser to a web

December 20th, 2007 by Mirjam
This blog has moved.  Click here to open this post on my new blog.

It happens quite often that I have to write a piece of code to set user permissions on a SharePoint site. One of the challenges you encounter when doing so is that you need to have a valid SPUser object, that is known in the site collection to be able to do this.

If you want to create a new subsite or web you can start out like this:

   // Open an existing site collection
   SPSite portalSite = new SPSite("
http://portal");
   // Create a new subsite (web)
   SPWeb newWeb =
    portalSite.AllWebs.Add("
http://portal/newweb", "My New WebSite", "This is my new web site", 1033, "STS#0", true,
                           false);
   // Get the default roledefinitions known on the new web
   SPRoleDefinitionCollection roleDefinitions = newWeb.RoleDefinitions;
   // Get the roleassignments collections of the new web
   SPRoleAssignmentCollection roleAssignments = newWeb.RoleAssignments;

Next you want to get an SPUser object, so you can give this person the right permissions on the site. Unfortunately there is no way of telling whether you can get this user from the site collection. If the user is known on the site collection there are three ways to get it:

   SPUserCollection users = portalSite.RootWeb.AllUsers;

The description in the SDK for this function is:
"Gets the collection of user objects that represents all users who are either members of the site or who have browsed to the site as authenticated members of a domain group in the site."
This means that if you have a site collection where you have authenticated all domain users by using an Active Directory group and the user we want to give the permissions to has never browsed to the site before this function won't return our user.

Next try:

   SPUserCollection users = portalSite.RootWeb.SiteUsers;

The SDK about this one:
"Gets the collection of all users that belong to the site collection."
Which means users explicitly added to the site collection.

And the last one:

   SPUserCollection users = portalSite.RootWeb.Users;

The SDK about this one:
"Gets the collection of user objects that are explicitly assigned permissions on the Web site."
So this only gets us the users that are explicitly to the web. And since we are actually trying to assign our user to the web we won't find him in this collection.

The way to solve this problem is to user SPWeb.EnsureUser(loginName) (I have to thank Donald for finding the solution!). The description in the SDK for EnsureUser is:
"Checks whether the specified login name belongs to a valid user of the Web site, and if the login name does not already exist, adds it to the Web site." Which happens to be exactly what we want!
Now we can finish our code:

   SPUser newUser = newWeb.EnsureUser(@"domainusername");
   newWeb.AllowUnsafeUpdates = true;

   // Create the new roleassignment that we want to add to the collection of roleassignments of the new web
   SPRoleAssignment roleAssignment = new SPRoleAssignment(newUser);
   SPRoleDefinitionBindingCollection roleDefBindings = roleAssignment.RoleDefinitionBindings;
   // Add the binding to the correct roledefinition to the roleassignment
   // This can also be Contribute for contributor rights.
   // Keep in mind that in sites in other languages this needs to be translated
   roleDefBindings.Add(roleDefinitions["Read"]);
   roleAssignments.Add(roleAssignment);
   
   newWeb.AllowUnsafeUpdates = false;

   newWeb.Dispose();
   portalSite.Dispose();

 Happy programming!