Category Archives: SharePoint Development

Problems with anonymous access to custom SharePoint list forms

A couple of days ago, I had troubles with anonymous access to a custom form for a custom list. I created a list, and added a DataFormWebPart to the page using SharePoint Designer as shown below.

41

I set the page and the list to allow anonymous access, and I could get to both. However, when I opened the page with the custom list form, the DataFormWebPart displayed the following error :

42

Resolution :

Just set DataSourceMode of SPDataSource control to Webs or ListOfLists as shown below :

43

For more information about the differences between Webs and ListOfLists, See this SharePoint Designer Team Blog post for a decent explanation of these options:

http://blogs.msdn.com/sharepointdesigner/archive/2007/04/24/spdatasource-and-rollups-with-the-data-view.aspx

 

Cached Timer Job Assemblies

Any time you update your custom timer job class and deploy the assembly to the global assembly cache, you must restart all the timer services in the farm. If you don’t restart the timer service, it will run the old copy of your timer job class. Yes, the timer service caches the assemblies. Restarting the SharePoint timer service is the only way to refresh the assembly cache and force it to use your updated assembly. You can achieve that from the command line using the following commands:

net stop sptimerv3
net start sptimerv3

Yes! I have learned that the hard way!

“SharePoint Troubleshooting” , A new free bonus issue of Understanding SharePoint Journal written by Me!

Just a quick note to let you know that a new free bonus issue of “Understanding SharePoint Journal” was released a couple of hours ago. The issue is titled “SharePoint Troubleshooting” and is written by me.

In that 25-page bonus issue, I will introduce you to some of the troubleshooting utilities, tools, tips, and tricks that can make your life easier in view of the fact that SharePoint troubleshooting can really be a nightmare for those who are new to the platform if it is not performed properly. The initiative for this issue came out of my late nights as a software engineer trying to troubleshoot SharePoint solutions to ship high-quality products on time.

39

You can get the issue for free from here.  I’ll also be waiting for your feedback for the issue atayman.elhattab@gmail.com

Announcing SPCountries

Have you ever found yourself in a situation where you need to create a SharePoint list that contains the names of all the countries of the world ? For me, I have faced this many times especially when developing public facing sites where I need to create forms and I need the form submitters to specify their countries of residence  along with other information.  The solution was very boring and time consuming, that is why I decided to share with you SPCountries which is a very simple feature that once activated, it creates a SharePoint list containing the names of all the countries of the world. Hope this helps 🙂

36

Get SPCountries from CodePlex : http://spcountries.codeplex.com

Forcing the execution of timer jobs

When you troubleshoot or test your custom timer job, you will probably want to instantly run the job without waiting for the job to run in schedule.

If you have observed the Timer job definitions in SharePoint central administration, you will find that it gives you the capability to disable the job definition but it doesn’t allow you to execute it.

23

Figure 1. You cannot force the execution of the jobs through the Central Administration.

Note : For the out of the box timer jobs, you can use the stsadm –o execadmsvcjobs command but this will merely execute the administrative timer jobs but it will not execute the custom ones.

One way to work around this is changing the job schedule, deactivating and activating the feature that installs the timer jobs; this will do the trick by altering the Schedule Property of the job. You can use SharePoint Manager 2007 for monitoring the timer jobs status, schedule and the last run time. It’s very useful and time-saving rather than writing custom code to retrieve those values.

24

Figure 2. Using SharePoint Manager 2007 to monitor timer jobs.

So the only solution to force custom timer jobs to execute is using SharePoint object model as follows. Below is a code snippet that does the trick

25

Note : Forcing a timer job to execute out of schedule will neither alter the LastRunTime property of the job nor modify the schedule, so don’t let that fool you.

UPDATE : After I have posted this blog post, I received a notification from Robin Meuré, informing me of a tool that he has recently created and shared with the community on CodePlex, the tool is really nifty!  It gives the administrators the ability to delete, disable and immediately run timer jobs from the browser without writing a single line of code. MARVELOUS!

26

I would like to extend a very special thank you to Robin for informing me of this tool.  Go get the tool from codeplex and I’ll be waiting here 🙂

Assembly Binding Log Viewer

Have you ever deployed your pages to SharePoint to have some binary files refusing to load and throwing the following exception?

31

Figure 1. File Not Found exception not specifying the failing assembly.

File Not Found.   at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)

Sometimes, it’s effortless to resolve this error by simply adding <%@Register> directives to reference some assemblies in your page markup, other times you will not be able to figure out what went wrong, it really could be lengthy and tiresome because the exception message never specifies the assembly that is failing to load. Luckily, Microsoft .Net Framework SDK comes with a very handy tool named “Assembly Binding Log Viewer” which can assist you diagnosing this issue.

The “Assembly Binding Log Viewer” keeps track of all assembly binding attempts that happen on your system. Although this tool ships with the .NET Framework, it’s really less known, this blog post will help you to get started with the Assembly Binding Log Viewer and understanding how you can use it to resolve this kind of exceptions.

a. Create a custom page and add the following Register directive at the top of the page :

<%@ Register Tagprefix=”UnderstandingSharePointJournal” Namespace=”USPJ.BonusIssue.SharePoint.Troubleshooting” Assembly=”USPJ.BonusIssue, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>

b. Go to Start >Microsoft Visual Studio 2005/2008 >Visual Studio tools->Visual Studio Command prompt and type fuslogvw. You will get a window similar to the one below.

32

 

Figure 2. Assembly Binding Log Viewer Window.

c. Click on the settings menu to bring up the settings for fuslogvw.exe. You have the choice to log all the binds that are happening or you can instruct the tool to only log the failures. It’s also very useful to capture those entries into your file system so that you can refer to them later on.
Note: One strange bug with Fuslogvw.exe is that unless you specify a custom logging directory, the logging won’t work…

33

Figure 3. fuslogvw.exe Settings dialog box.

d. Run IISRESET from the command prompt.

e. Navigate to your page from your web browser to reproduce the issue.

f. Click the Refresh button in the window.

34

Figure 4. fuslogvw.exe monitoring all the bind failures.

g. Now you can search for the failures and find out which assembly is causing the page to crash. In our case, the .NET framework wasn’t able to locate the assembly USPJ.BonusIssue at runtime. You can double-click any of the entries in the main window to see exactly how and what the .NET runtime was doing to look for the assemblies your page referenced.

35

Figure 5. More information about the failure by double clicking the entry.

Global Exception Handling in SharePoint

In many cases, you might want some form of centralized exception handling rather than surrounding every piece of code with Try Catch blocks. You also might want some way to log and handle unhandled exceptions and forward the end user to an error page which has the same look and feel of your site collection rather than the silly error page shipped with SharePoint. In point of fact, there is nothing worse than an error being thrown at the face of the end user and you cannot figure out what caused the problem because the exception is unhandled and it is not revealed anywhere in the log files.

A great way for centralized logging, exception handling and providing a friendly error page is to employ a global exception handler at the application level. This will catch any unhandled exceptions, log them, clear them and redirect the user to a fully branded page. You can also extend your global exception handler to send notification mails to the site collection administrator informing him/her that an unhandled exception has occurred.

The way you can implement global exception handling in regular ASP.NET applications is via the Global.asax file which can enclose code that responds to application-level events. These are events that are raised at specific points during the running of the asp.net application. One of those events is the Application_Error event which fires whenever an unhandled exception occurs in the application; the next code snippet demonstrates the Application_Error event.

protected void Application_Error(object sender, EventArgs e)

{

// Code that runs when an unhandled error occurs

Exception unhandledException = Server.GetLastError().GetBaseException();

SharePointLogger.LogException(unhandledException);

Server.ClearError();

Server.Transfer(“FriendlyErrorPage.aspx”);

}

Commence the Windows Explorer and navigate to the physical root directory of your SharePoint web application, there you should see the global.asax file. SharePoint automatically adds this file every time you create a new SharePoint web application. If you open this file in Visual Studio, you should see the following:

27

Figure 1. Global.asax file for SharePoint web applications.

As you see, the global.asax file contains two directives. The @Assembly directive references the Microsoft.SharePoint.dll assembly, which contains the ApplicationRuntime namespace. Note that the Inherits attribute of the @Application directive instructs ASP.NET to use SPHttpApplication as the base class for the class that it dynamically creates and instantiates. Let’s use the .NET Reflector to investigate this class; the next figure demonstrates this in action. If you don’t know what .NET Reflector is, refer to the “Troubleshooting Toolbox” section at the end of the issue.

28

Figure 2. Using .NET Reflector to investigate SharePoint Global.asax.

As you might have concluded, you cannot trap unhandled exceptions through Global.asax; this place has been taken by the product itself. Alternatively, you need to hook into the ASP.NET HTTP pipeline by creating an HTTP Module. The next figure shows a sample HTTP Module that you can start with to create your own global exception handler.

30

Figure 3. Using HTTP Module to globally handle and log unhandled exceptions.

SharePoint Logging Library

In my article “Simplifying SharePoint Debugging By Creating the Troubleshooting Toolbox“, I have stated the following :

“I’d also like to point out that you can write code that incorporates logging to MOSS logs. Writing to the same trace log alleviates the need for developers to log their development information in other places such as the Windows Event Log, which is more commonly used by system administrators.”

 

Unfortunately this comes with 3 gotchas :

  1. You cannot set the log event level (e.g. low, medium, and critical) as it’ll always display the error level in the trace logs as High.
  2. Also you cannot control the trace category as it’ll always display the category as “General”.
  3. The logger is located in 12\ISAPI \Microsoft.Office.Server.dll and therefore it’s only available with the MOSS install, not WSS 3.0.

What if you need to write into SharePoint trace logs while having full control on the error level and category?

Enter SharePoint Logging Library !

  1. Get the “SharePoint Logging Library” from CodePlex.

 

    21

  1. Add a reference to AymanElHattab.SharePoint.Logging.dll .
  2. Add a using statement to AymanElHattab.SharePoint.Logging namespace.
  3. Use the library as follows :

    SharePointLogger.LogStartOfMethod();
    SharePointLogger.LogWarning(“Hello SharePointers”);
    SharePointLogger.LogInformation(“x = ” + x);
    SharePointLogger.LogMessageWithSeverityAndCategory(“Hi”, SharePointLogger.TraceSeverity.High, “My Category”);
    SharePointLogger.LogEndOfMethod();

  4. Get your code executed , then open the trace logs.

22

 As you might have noticed :

  1. You can call the public methods SharePointLogger.LogStartOfMethod() and SharePointLogger.LogEndOfMethod() for writing to SharePoint Trace Logs .You don’t need to pass the method or class name, this will be automatically logged by Reflection as shown in the figure above : “Beginning of NameSpace.ClassName.MethodName Method”.
  2. You can control the severity and the category when you use the LogMessageWithSeverityAndCategory() Method.
  3. “General” is the default category when you use the methods that doesn’t accept a parameter for the category.
  4. You can log exceptions and their stack traces by passing the exception object to the public LogException() Method.

Getting the Login Name for a Given Display Name in SharePoint

Yes, It’s possible to retrieve the LoginName of a user if you only have the DisplayName ( Last Name + First Name ).

There are a lot of ways to achieve that like :

  1. You can directly query the Active Directory.
  2. You can use a PeopleEditor control, which will grab the user if you type in the lastname, firstname combination as follows :
    PeopleEditor people = new PeopleEditor(); people.MultiSelect = false;
    this.Controls.Add(people);
    int userID = Int32.Parse((((PickerEntity)people.ResolvedEntities[0]).EntityData[“SPUserID”]).ToString());
    SPUser user = SPContext.Current.Site.RootWeb.SiteUsers.GetByID(userID);
  3. You can use SharePoint Search API ( FullTextSqlQuery Class ) :
    SELECT AccountNameFROM portal..scope()WHERE ( (“SCOPE” = ‘People’) ) AND (“Title” = ‘[DISPLAY NAME]’)

I prefer the third way, much easier.

Using Surveys on anonymous access SharePoint sites

One of the nice features of SharePoint is “Surveys”. They allow you to create a set of questions and have users of the site fill them in. It allows for selections from a set list, rating scales (where you rate a number of items along a scale from, say, ‘not at all’ to ‘extremely’) and even flow logic (where the outcome of one question causes certain questions to be skipped). For intranet-type team sites, this just works like a charm. For public sites with anonymous access however, it turns out not so easy. To fill out a form, the user must have write access to the surveys library for example. Normally, we of course never allow write access to anonymous users. This article will show you how to configure your survey for use on a public anonymous web site (it involves a little trick). Note that this tutorial applies to ALL flavors of SharePoint, both WSS 3.0 as any of the MOSS 2007 licenses.