Friday, December 28, 2007

MCTS: .NET Framework 2.0 Web Applications

Yesterday, I passed the 70-528 exam, so yes, I'm a Microsoft Certified Technology Specialist in .NET Framework 2.0 Web Applications now! What a mouthfull... I'm glad I got through it in one time, seeing how I had to study it during the holidays...

If you're taking the exam too and you want some general pointers: both custom controls and personalization were really important topics on my exam. However, don't focus on these two topics too much, since every exam can be completely different... But they did form a large part of my exam, so it won't hurt you to reread these topics an extra time.

Sunday, December 9, 2007

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

If you ever get the error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt.", take a look at the rest of this post, it might save you a lot of time... I got it when writing a console application for SharePoint, but I think it might occur with other sorts of applications too.

I had been looking for a solution for many days and had seen lots of possible causes online, but none of them applied to my situation. Today, I noticed for the first time that Visual Studio gave me a warning when building. I hadn't noticed this before because there weren't any errors, so it just said "build succeeded", so I thought everything in my application was fine and it must have been something about the setup of the test server. Well, I clearly was wrong... Here's what the warning said:

Found conflicts between different versions of the same dependent assembly.

When double clicking this warning, Visual Studio asks you if you want it to fix the errors by adding binding redirect records in the app.config file. If you choose "yes", then Visual Studio adds some lines to the app.config file. Here's what it added for me:

<runtime>

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

<dependentAssembly>

<assemblyIdentity name="Microsoft.SharePoint.Library" publicKeyToken="71E9BCE111E9429C" culture="neutral"/>

<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>

</dependentAssembly>

<dependentAssembly>

<assemblyIdentity name="Microsoft.SharePoint" publicKeyToken="71E9BCE111E9429C" culture="neutral"/>

<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>

</dependentAssembly>

<dependentAssembly>

<assemblyIdentity name="Microsoft.SharePoint.Security" publicKeyToken="71E9BCE111E9429C" culture="neutral"/>

<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>

</dependentAssembly>

<dependentAssembly>

<assemblyIdentity name="Microsoft.SharePoint.Dsp" publicKeyToken="71E9BCE111E9429C" culture="neutral"/>

<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>

</dependentAssembly>

</assemblyBinding>

</runtime>


Now just rebuild your project and try running it again... Everything should be working fine now!

Monday, November 26, 2007

Enabling the language switch in SharePoint

Today someone at work pointed out that there was a switch control in SharePoint that allows users to easily switch between the different languages a page is available in. I hadn't heard of this already, so if you haven't either, now you've got no more excuses to say you don't!

Now what exactly does it do? Quite easy... If variations are enabled and there's a version of a certain page available in a different language, a switch will show up to easily switch between the different versions of the page. If your page only exists in English for example, the switch control won't show up.

But most importantly... How do you enable it? Well, that's easy too. All you need to do is follow some simple steps:

- Go to the ...\12\TEMPLATE\CONTROLTEMPLATES folder and open the VariationsLabelMenu.ascx file.

- Look for the line that's commented out. Remove the comment tags to enable the control. Here's the line you should comment out:

<cms:VariationsLabelEcbMenu id ="varlabelmenu1" DataSourceID="LabelMenuDataSource" DisplayText="<%$Resources:cms,VariationLabelMenuTitle%>" IsCallbackMode="true" runat="server" />

- Now go to the Master Page you want to include the control in and make sure that it has the following tag at the top:

<%@ Register TagPrefix="PublishingVariations" TagName="VariationsLabelMenu" src="~/_controltemplates/VariationsLabelMenu.ascx" %>

If this tag is on your Master Page and you've commented out the control, then the switch control should be showing right beside the links in the upper right corner of the Master Page. Now you can use this control and put it where ever you want to. If you want, you can also use it like this:

<PublishingVariations:VariationsLabelMenu id="labelmenu1" runat="server"/>

Easy as that!

Thursday, November 8, 2007

Cannot update. Database or object is read-only.

In Access 2007 you have a great feature that can copy data from or to a SharePoint list, but the error messages could have been better...

While copying a whole bunch of data, I got the following error:

Cannot update. Database or object is read-only.

Very vague... Looking at the record that caused the error (another great feature of the new Access, it shows which records couldn't be copied) I saw nothing strange. When googling for the error message, I even found a page telling that this was a known issue with a Hotfix for it, so I first thought that there was no way for me to solve this error quickly. When taking another look at the record though, I noticed a multiline field I overlooked. At the end of this field, there was a strange sign (a question mark in a little square), which was obviously causing the error...

So, long story short, if you ever run into this error, just check your data (all of it, don't be like me...) and try copying field by field to determine the field with the "illegal" character.

Wednesday, November 7, 2007

Files uploaded programmatically don't work for all users

Files uploaded programmatically don't work for all users

Today I encountered a problem when uploading images in a feature. Everything seemed to work fine, the images (used in my master page) appeared nicely where they should be, but then I logged in as another user and it just showed me the typical red x's. I noticed that the images were still checked out to the Administrator, so I checked them in programmatically and... still nothing. At first I thought they were not visible due to some kind of permissions problem, but the real solution was that you also need to publish a major version of the file. So if you ever upload files through code, do not forget these lines:

//Upload the new file.
SPFile addedFile = destinationFolder.Files.Add(fileName, fileToAdd.Open(FileMode.Open));

//Check in the newly created file and then publish a major version of it.
addedFile.CheckIn("File checked in by activating FodCustomLayout feature.");
addedFile.Publish("File published by activating FodCustomLayout feature.");

Monday, October 15, 2007

Automatically applying a master page upon activating it as a feature

Today, I was facing the problem of making all My Sites use the same master page. I figured this would be possible through feature stapling, by providing the master page to every newly created My Site. The problem here was that it did copy the master page to the master page gallery, but it did not selected it yet. To do this, I found a great solution thanks to Paul Papanek Stork.

If you want the complete explenation, you can read it all through on his blog. The key I needed was the following bit of code which will fire when activating or deactivating the feature:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace CustomMaster
{
public class ChangeMaster:Microsoft.SharePoint.SPFeatureReceiver
{
public override void FeatureInstalled (SPFeatureReceiverProperties properties)
{
}

public override void FeatureUninstalling (SPFeatureReceiverProperties properties)
{
}

public override void FeatureActivated (SPFeatureReceiverProperties properties)
{
SPWeb CurrentWeb = properties.Feature.Parent as SPWeb;
CurrentWeb.MasterUrl = "/_catalogs/masterpage/MyDefault.master";
CurrentWeb.CustomMasterUrl = "/_catalogs/masterpage/custom.master";
CurrentWeb.Update();
}

public override void FeatureDeactivating (SPFeatureReceiverProperties properties)
{
SPWeb CurrentWeb = properties.Feature.Parent as SPWeb;
CurrentWeb.MasterUrl = "/_catalogs/masterpage/default.master";
CurrentWeb.CustomMasterUrl = "/_catalogs/masterpage/default.master";
CurrentWeb.Update();
}
}
}

Just build the feature as Paul describes it, include your own custom master page in the solution and then write a stapling feature that binds this master page feature to the "SPSITE#0" template. Every new My Site will now automatically use your custom master page. Of course, this will also work for every other site template and if you also want the whole portal to automatically use this master page, then use the "GLOBAL" template when stapling your feature.

Tuesday, October 2, 2007

Error: The type or namespace name 'Publishing' does not exist

Here's something useful I've learned today...

I had created a custom master file and included this line:

<img runat="server" src="<% $SPUrl:~SiteCollection/Style Library/Images/~language/LocalLogo.JPG%>" alt="Logo"/>

This line had to provide a localized site logo for a MOSS 2007 site. When I tried using the master page, I got the following error:

An error occurred during the compilation of the requested file, or one of its dependencies. The type or namespace name 'Publishing' does not exist in the namespace 'Microsoft.SharePoint' (are you missing an assembly reference?)

After quite a long search (at least for such a "small" problem), I finally found the solution on Clever Workarounds. Apparently, the error was that I had used the Default.master file to start my custom page from. This masterpage doesn't support Publishing by default though (as opposed to Blueband.master for example), so you have to add these following assembly declarations to your custom master page:

<%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="PublishingVariations" TagName="VariationsLabelMenu" src="~/_controltemplates/VariationsLabelMenu.ascx" %>
<%@ Register Tagprefix="PublishingConsole" TagName="Console" src="~/_controltemplates/PublishingConsole.ascx" %>
<%@ Register TagPrefix="PublishingSiteAction" TagName="SiteActionMenu" src="~/_controltemplates/PublishingActionMenu.ascx" %>


That should do the job...

Thursday, September 27, 2007

How to brand your SharePoint site with your company's logo

Today someone at work asked me to do a little research on which options there are to add a company logo to a SharePoint 2007 environment. This is quite a basic customization and I thought of a couple of options myself and did some further research on what other people had written. There are (as far as I see it) 4 options to do this:

- Change the logo through the Site Settings (by using the "Title, description, and icon" option). While this is really easy and this doesn't require any coding or designing, the problem with this is that it only changes the logo for the current site, so subsites won't get changed this way.

- You could write a simple command line tool that loops through all your sites and subsites and changes the logo by using SPWeb.SiteLogoUrl. While this is a good way to make sure that every single site gets the new logo, it does require you to run it again when adding new sites.

- A way to make sure that every single site uses the new logo, is to replace the default "titlegrapic.gif" with a new image (of course, backup the default image, you never know...). The image can be found under C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\IMAGES.

- The last way to replace the site logo is to make a custom master page. In this master page, you replace the placeholder for the site logo with a link to your own logo. Now assign the new master page to your site collection and let it's subsites inherit this master page.
For more info on how to do this one, check out Shane Perran's blogpost.


If you have another suggestion on how to do this, feel free to add it!

Thursday, September 20, 2007

Finally on Google!

Wow, I almost forgot about this blog... It just wouldn't show on google, no matter how I searched for it, so I kind of gave up on it. But I was just trying it again out of curiosity and to my great surprise, it shows up now!! I'll try posting again every once in a while now...

While I'm at it, just something I wanted to share with everyone. You know Disneyland Paris? I've been there for four days last week and I'm not going to give you a whole detailed summary of my trip, but there's one thing I just had to share: VISIT CRUSH's COASTER!! It's a new attraction in the Walt Disney Studios park and it's one of the best roller coasters I've ever been on! No loopings or other fancy twists, but just a fast, thrilling, spinning ride in an awesome scenery... If you ever visit the park, this is a must-do!

Wednesday, April 18, 2007

Creating a document library with a view with grouping in MOSS programmatically

For this project I'm on at the moment, a document library needed to be created programmatically. It needed a view and inside the view, a grouping had to be made.

To do this, I found some info on the various steps on some blogs, msdn, ... but I hardly found anything about grouping. This is why I thought it would be useful to post a code example of the whole thing: creating a document library, creating a view on it and creating a grouping.

The code is fairly simple once you know it, so I won't go any deeper into it. If you've got any questions though, feel free to ask!

WebToAddLibraryTo.AllowUnsafeUpdates = true;

SPListTemplate listTemplate = WebToAddLibraryTo.ListTemplates["Document Library"];

System.Guid guidLib = WebToAddLibraryTo.Lists.Add("Title", "Description", listTemplate);
WebToAddLibraryTo.Update();

SPList docLib = WebToAddLibraryTo.Lists[guidLib];

docLib.EnableVersioning = true;
docLib.EnableMinorVersions = true;
docLib.OnQuickLaunch = true;

docLib.Fields.Add("Field name", SPFieldType.Text, true);
docLib.Fields.Add("Another field name", SPFieldType.Text, false);
docLib.Fields.Add("Date field", SPFieldType.DateTime, false);
StringCollection resultStrings = new StringCollection();
resultStrings.Add("Positive");
resultStrings.Add("Negative");
docLib.Fields.Add("Result", SPFieldType.Choice, false, false, resultStrings);

StringCollection viewFieldCollection = new StringCollection();

viewFieldCollection.Add("DocIcon");
viewFieldCollection.Add("LinkFilename");
viewFieldCollection.Add("Another field name");
viewFieldCollection.Add("Date field");
viewFieldCollection.Add("Result");

string defaultQuery ="<GroupBy Collapse=\"TRUE\" GroupLimit=\"100\">" +
"<FieldRef Name=\"Field name\">" +
"<FieldRef Name=\"ContentType\">" +
"</GroupBy>" +
"<OrderBy>" +
"<FieldRef Name=\"LinkFileName\">" +
"</OrderBy>";


Guid oldViewId = docLib.DefaultView.ID;
docLib.Views.Delete(oldViewId);

SPView newView = docLib.Views.Add("New view", viewFieldCollection, defaultQuery, 100, true, true, SPViewCollection.SPViewType.Html, false);

docLib.DefaultView.Update();

docLib.Update();

Thursday, March 1, 2007

Just something weird while downloading something big...

I just started downloading the trial image of Visual Studio 2005, which is 3.3GB large and in stead of counting up, the download is counting down... It went from 0%, to -1% and right now it's at -7%. Here's a little screen to prove it:


download















Weird... Can't wait for the download being complete at -100%

EDIT: Well, it went way past -100% to something like -200% and then all of a sudden, it went to 393% and now it's counting down from there... I don't have a clue why this is (probably just a miscalculation), but it sure is funny.


download

Monday, February 5, 2007

How to add a BestBet in SharePoint 2007 programmatically

First of all: hi! I'm Tom, software engineer at Dolmen (you know, the company where the infamous jopx works, not by coïncidence the person who I report to...). It took me a while to start blogging, but when I was looking for information on adding BestBets and Keywords programmatically and I couldn't find a thing, it just felt like the right moment to start a blog and "share the wisdom" as they say. Adding Keywords and BestBets is actually not that difficult, you just have to know the right syntax to do so. That's where I come in: here's what I did to make it work:

bool found = false;

Keywords keys = new Keywords(SearchContext.GetContext(SPContext.Current.Site), new Uri(SPContext.Current.Site.Url));

foreach (Keyword key in keys.AllKeywords)
{
if (key.Term.ToLower() == textToCompareTo.ToLower())
{
found = true;
bool foundBet = false;

foreach (BestBet bet in key.BestBets)
{
if (bet.Url == urlToReferTo)
{
foundBet = true;
}
}

if (!foundBet)
{
key.BestBets.Create("Title", "BestBet description", urlToReferTo);
}

break;
}
}
if (!found)
{
keys.AllKeywords.Create(textToCompareTo.ToLower(), DateTime.Now);
}


Now let's explain what this code does...

To start off, we create a boolean that tells us whether the Keyword we want to add a BestBet for is already in the Keywordcollection or not. If it isn't, we'll add it at the end of our code.
The next step is to get all the Keywords of the current Sitecollection you are working on. To do so, we need to create a new Keywordcollection with the context of the current Sitecollection and the url of this Sitecollection.
Once we've found the Keywords, we're going to browse through all the Keywords of the current Sitecollection to check for a match with the Keyword you want to add a BestBet for (in the example I've just used "textToCompareTo" as the string we're looking for). If we find this Keyword in the Keywordcollection, we're going to browse through all the BestBets that have been assigned to this Keyword, to check whether the BestBet we want to add is already part of the BestBetcollection or not. If it is, then our job is done and we don't have to do a thing anymore. If it isn't, we'll add it by creating a new BestBet with a certain title, description and an url we want the BestBet to refer to.

So there you go, not that hard as I first thought it was going to be. If there's any questions or remarks, feel free to leave a comment.