Skip to content
/

I have a clean install on the latest and greatest: Windows Server 2008, SQL Server 2008 and MOSS 2007 SP1 with all updates.
Everything works fine, except the search crawl gave Access Denied errors on http://mysite and sps3://mysite.
This post explains how I fixed the problem.

I have a clean install on the latest and greatest: Windows Server 2008, SQL Server 2008 and MOSS 2007 SP1 with all updates. This is the layout of my farm:

http://<server>:80 - Portal
http://<server>:8000 - Central Admin
http://<server>:8001 - SSP
http://mysite - MySites

Everything works fine, except the search crawl gave Access Denied errors on http://mysite and sps3://mysite. I checked everything, but could only find this in the Application event log:

The start address <http://mysite> cannot be crawled.
Context: Application 'SharedServices1', Catalog 'Portal_Content'
Details:
Access is denied. Check that the Default Content Access Account
has access to this content, or add a crawl rule to crawl this
content.   (0x80041205)

Also the Secutiry event log says:

An account failed to log on.
Subject:
Security ID:              NULL SID
Account Name:             -
Account Domain:           -
Logon ID:                 0x0
Logon Type:               3
Account For Which Logon Failed:
Security ID:              NULL SID
Account Name:             <DCA account>
Account Domain:           <Domain>
Failure Information:
Failure Reason:           An Error occured during Logon.
Status:                   0xc000006d
Sub Status:               0x0
Process Information:
Caller Process ID:        0x0
Caller Process Name:      -
Network Information:
Workstation Name:         <Server>
Source Network Address:   127.0.0.1
Source Port:              50678
Detailed Authentication Information:
Logon Process:
Authentication Package:   NTLM
Transited Services:       -
Package Name (NTLM only): -
Key Length:               0

I had a hard time finding the solution, until I encountered Ron Grzywacz's Blog: Crawling Issue with .NET 3.5 SP1.

Although KB896861 only mentions Windows XP and Windows Server 2003, it seems to fix the issue on Windows Server 2008 as well.

So to fix this:

  1. Click Start, click Run, type regedit, and then click OK
  2. In Registry Editor, locate and then click the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
  3. Right-click MSV1_0, point to New, and then click Multi-String Value
  4. Type BackConnectionHostNames, and then press ENTER.
  5. Right-click BackConnectionHostNames, and then click Modify
  6. In the Value data box, type the host name or the host names for the sites that are on the local computer, and then click OK
  7. Quit the Registry Editor, and then restart the IISAdmin service

It worked immediately!

/

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(SPSiteSite,stringWebUrl)

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(stringbaseUrlPath,stringadditionalNodes)

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!