Skip to content
/

While working on a project with some existing code I noticed the developer did write large portions of code to get from an URL to a SPList. He probably didn’t know some of the hidden gems in SharePoint.

While working on a project with some existing code I noticed the developer did write large portions of code to get from an URL to a SPList. He probably didn't know some of the hidden gems in SharePoint.

Get the full URL

Sometimes you need the full URL and only have the relative one. For example when opening a new SPSite or when writing code in a SPNavigationProvider. For this you could use the SPUtility Class:

SPUtility.GetFullUrl(SPSite Site, string WebUrl)

For example:

string webUrl = "/sub/default.aspx";
SPUtility.GetFullUrl(SPContext.Current.Site, webUrl);
    // "http://localhost/sub/default.aspx"

There is one catch:

string webUrl = "http://localhost/sub/default.aspx";
SPUtility.GetFullUrl(SPContext.Current.Site, webUrl);
    // "http://localhosthttp://localhost/sub/default.aspx"

Check the type of URL

The former example is nice, but you would still need to write code to check if the input already contains the full URL. Nope!

For this, two gems are found in the SPUrlUtility Class.

SPUrlUtility.IsUrlRelative(string url);
SPUrlUtility.IsUrFull(string url);

These methods do exactly what their names imply: check if the URL is relative or full. So for example:

string fullUrl = "http://localhost/sub/default.aspx";
string relUrl = "/sub/default.aspx";
SPUrlUtility.IsUrlRelative(fullUrl); // false
SPUrlUtility.IsUrlRelative(relUrl);  // true
SPUrlUtility.IsUrlFull(fullUrl);     // true
SPUrlUtility.IsUrlFull(relUrl);      // false

Great! Now we can combine the two:

if (string.IsNullOrEmpty(webUrl) || SPUrlUtility.IsUrlRelative(webUrl))
{
    webUrl = SPUtility.GetFullUrl(SPContext.Current.Site, webUrl);
}

Now webUrl will always be the full URL.

URL concatenation

Ever did web.ServerRelativeUrl + "/something" and found out it did work nicely except it start doing something really weird on your root web? On the rootweb the relative URL is /, and this results in the URL //something which on it's own turn gets translated to http://something, and that URL doesn't exist (most of the time).

When working with file system locations, you should always use Path.Combine() instead of concatenating path's yourself. But there is no Uri.Combine().

You could write an extension method. But the SharePoint team made it more easy.

SPUrlUtility.CombineUrl(string baseUrlPath, string additionalNodes)

This method does the same thing like Path.Combine(). For example:

string root = "/";
string path = "/sub"
string doc = "/sub/default.aspx";
SPUrlUtility.CombineUrl(root, path); // "/sub"
SPUrlUtility.CombineUrl(root, doc);  // "/sub/default.aspx"
SPUrlUtility.CombineUrl(path, doc);  // "/sub/sub/default.aspx"

That's the final (hidden) gem for today.

/

Sometimes you have to split your code into different assemblies. For example when I created a custom Admin Page which inherits from WebAdminPageBase (Microsoft.SharePoint.ApplicationPages). The problem with Microsoft.SharePoint.ApplicationPages is that it's not deployed to the GAC.
When compiling you will get the following message: “CS0122: 'foo.bar.x' is inaccessible due to its protection level”

Now you have only one choice: make x public. Or maybe not?

Sometimes you have to split your code into different assemblies. For example when I created a custom Admin Page which inherits from WebAdminPageBase (Microsoft.SharePoint.ApplicationPages). The problem with Microsoft.SharePoint.ApplicationPages is that it’s not deployed to the GAC.

Putting a reference to this assembly from my assembly, also containing custom web parts and other controls which have to be registered as SafeControls in the web.config, will result in deployment troubles when you use a WSP file. The problem is when SharePoint is going to register the safecontrols it will reflect your assemby and won't be able to access the Microsoft.SharePoint.ApplicationPages assembly because it’s not available in the GAC.
The same problem can be found using the Content Deployment option.

So you split your code in 2 assemblies, for example foo.bar and foo.bar.ApplicationPages. But when your custom application page is depending on an internal type declared in foo.bar you are in trouble. When compiling you will get the following message:

"CS0122: 'foo.bar.x' is inaccessible due to its protection level"

Now you have only one choice: make x public. Or maybe not?

The solution

It’s also possible to make your assembly share it's internals with other assemblies. Add the following to you code (in foo.bar):

[assembly: InternalsVisibleTo("foo.bar.ApplicationPages, PublicKey=0a240a ... c2f34c7")]

But the public key is not your public key token. Thanks to Burt Harris’s comment at the InternalsVisibleToAttribute Class you can find your real public key using the following command:

sn.exe -Tp foo.bar.dll

Now compile your project and there you go!