Debugging tips for SharePoint-转

http://blog.thekid.me.uk/archive/2007/07/25/debugging-tips-for-sharepoint-and-wss-exceptions.aspx

 

Debugging on SharePoint is much the same as debugging any otherASP.Net application...you can use the same techniques. Here are some ofmy tips for diagnosing & solving your problems...

Debugging starts with your first line of code

As you start writing some code you need to bear in mind that at some point you willneed to debug it. This may mean attaching a debugger (easy) or lookingat a crash dump (hard). This means debugging should always be at theback of your mind when writing any code...ask yourself "when this islive how am I going to find out what has gone wrong?"

In practice this means making full use of the features of .Net ... System.Diagnostics, try...catch, exception logging,etc. One thing in particular to remember is that if you do ever have tolook at a crash dump your variable & method names will be in theretoo. The more descriptive they are the easier it is going to be toanalyse the dump. Also bear in mind that the less code in each methodthe easier it will be to pin-point the location of the error. Les Smith has some good points to make about refactoring...I would add that refactoring making debugging easier!

Use Trace.Write & Debug.Write

This is the first thing I would recommend. Adding these method callsat suitable places in your code can really help to solve problems. Usedin conjunction with DebugView these methods can give you great insight to what is happening within your code. Personally I use Tracewhenever something unexpected or 'out of the ordinary' occurs, normallyexceptions, but it could be anything that may help solve a problem.Calls to the Trace methods remain in release code and so will add an overhead to the code execution. I generally use Debugto enable me to see code execution paths during development and asthese do nothing in a release build can be used much more liberally.

Using the Trace statements canreally help when you cannot attach a debugger (on a live server) togive you more information of what has gone wrong. If you ensure you usetry...catch...finally blocks throughout your code, using Traceto log the exception makes it easy to see where the error has occurred(including the call stack) simply by running DebugView on the server.

Use try...catch...finally

When developing ASP.Net controls and WebParts I like to add try...catch blocks when overriding methods like OnInit, OnLoad, CreateChildControls and Render.I do this because I don't what the whole page to fail to render simplybecause one control has a problem...If the search box control throws anexception, why shouldn't the rest of the page display? Therefore myRender method would look like this...

protected override void Render(HtmlTextWriter writer)
{
    try
    {
       // Do something to render the control, which may cause an exception
    }
    catch (Exception ex)
    {
       Trace.Write(ex);
       Trace.WriteLine(HttpContext.Current.Request.Url.ToString());
       // Maybe render an error message
    }
}

This way if an exception is thrown the page will still render...theuser may not get the full functionality of the page, but at least theyget something. Essentially wrapping your code in a try...catchblock has a negligible hit in terms of performance and so you shouldlook to using them wherever something may throw, even if you just Traceand re-throw the exception. Also you should bear in mind that throwingan exception is a big overhead and should only be used when areal exception has occurred...something you really did not expect andcannot recover from.

Check the SharePoint log files

These will be located in the /12/LOGSfolder. The log files contain errors & messages generated bySharePoint. I have to say that generally they don't give you as muchinformation as you would like (sometimes nothing), but occasionallythey point you straight to the problem. Either way you should alwayscheck them just in case.

You should also know that you can increase or decrease the amount oflogging SharePoint does in Central Administration. Here you can changethe verbosity of the logging within different parts of the application.Its not the easiest interface to use, but you can increase the numberof messages logged...doing this has solved problems for me in the past.

You change the settings under 'Logging and Reporting' in the operations tab...

 

Clicking on diagnostic logging shows the following page...

Under 'Event Throttling' you can change the verbosity. I have to saythat I normally just set all of the categories to verbose when I have aproblem as it can be difficult to identify the categories which you mayneed to change.

Here you also see the 'Trace Log' settings with the defaultsettings...generally I like to make these smaller, say 30 files and 5minutes. This makes the log files smaller and easier to view.

Use all the tools available to you

There are a lot of tools out there to help you resolve yourproblems, get to know them, know what they can do and when they canhelp. This is a list of tools I use on a regular basis...

There are more tools avaiable, what you use depends on the problem you are trying to solve, in particular tools like U2U's CAML Builder can help you to replicate problems.

Don't try to guess

Don't try guessing what the problem might be and randomly changingyour code to try and fix it (although this maybe a last resort!!!). Attach a debugger,look at the code, trace through the code and find the cause. If youneed to, you can even break the debugger in SharePoint code, it maybeIL, but it is better than nothing. Reflector can really help in this situation as it gives you a chance to relate the IL code back to C#.

I had an example of this recently, the authoring console was giving me the following error...

No errors were logged anywhere and I couldn't see what could becausing the problem, but it was preventing us from authoring. To solvethe problem I attached the VS.Net debugger to the w3wp process,disabled 'Just My Code' and set the debugger to break on allexceptions...

 

I then refreshed the page and broke into the SharePoint code when the exception occurred...

Once in the debugger we can see that we have a NullReference exception thrown in a method called ConfigurationXml() in the ConsoleXmlUtilitiesclass. None of these details were logged, but now I know exactly wherethe problem is manifesting itself. Now we have the class and the methodwe can use Reflector to see what is going on...

Looking at the ConfigurationXml method we can see where a null reference 'may' occur. Reading through the code shows that the most likely suspect is that file2 is being used without checking to see if it is null (digging into the configFilemethod shows us this is a valid return value). Using reflector shows usthat this class is dealing with the configuration files for theconsoles located in the Master Pages gallery. A quick check showed thatnone of the XML files in the Editing Menu folder had un-publishedversions (I still don't know how that happened). Publishing those filessolved the problem!

This shows how simple it can be to resolve a problem, even when it is occurring within the SharePoint code base.

Re-produce & isolate the problem

Most of the time your problem will occur within the complex sequenceof events of a webpage request. You can try to narrow down thepossibilities by executing the same code in a different context.SharePoint actually gives you a really quick and easy way of doing thiswithout having to deploy binaries...in the form of the _layouts folder.

You can easily create a quick .aspx page containing the code whichis causing problems. This you can place in the _layouts folder to test.In the .aspx page you can add whatever Trace, Debug or Response.Write callsyou like to see what is going on...you can see exactly what is going onwithout having to attach a debugger. This technique can work reallywell on live servers where you haven't got VS.Net and Notepad is theonly tool available.

If the .aspx doesn't give you what you want, a console application or Snippet Compilercan also work well. The general idea here is to re-produce the problemin a different environment which should help to narrow down the cause.

Debug on the live server

Sometimes, no matter how hard you try, you cannot reproduce an errorwithin a test environment...it only happens on the live server. If yourTrace statements are not giving you the details you require then youare going to have to debug the problem on the server causing theproblem. Fortunately there are a number of solutions to this problem.

If you have a connection for which the firewall allows remote debuggingyou can copy some files across to the live server and attach thedebugger from your development machine...this will obviously work bestwith a debug build deployed. Debugging remotely actually works verywell, but it will prevent the server from processing requests, thismeans the server will be unavailable whilst you perform yourdebugging...which might be early Sunday morning...the only time you canmake the server unavailable!

If you can't get through the firewall then you can use WinDbgto debug on the server. This will allow you to attach to processes andstep through code. It is actually more powerful than VS.Net, but isharder to use as, even though it has a UI, it relies on a cryptic setof commands to get it to do what you want. Even so, it is well worthusing as it can give you access to valuable information.

To give you a comparison, the following is the same debugging process in WinDbg as the previous example in VS.Net.

Firstly attach to the w3wp process...

Once attached you will need to load the SOS.DLL to give you access to the debugging functions you'll need. You can use the following command to achieve this...

.load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll

You now need to tell the bugger to stop on .Net exceptions. Do this with the following command...

sxe CLR

You can now continue the debugging by entering go(or click on the icon) and wait for the exception. When the exceptionis thrown the debugger will break and you will see the following in thecommand window...

 

As you can see we have hit an exception on the same line of code aswe did in VS.Net. We can now look at the call stack using the command !clrstack, which produces the following results...

 

This again shows us the WSS class and method in which the error occurred. Here you could also enter !clrstack -p,which would show you the parameters and the memory addresses. If youwant you can look at the method parameters using the command !dumpobject...

0:015> !clrstack -p
OS Thread Id: 0x50d4 (15)
ESP       EIP    
01c7ebe4 0bd81a4b Microsoft.SharePoint.Publishing.WebControls.ConsoleXmlUtilities.ConfigurationXml(System.String, Boolean)
    PARAMETERS:
        configProvider = 0x0e843368
        isBuiltInConfigFile = 0x00000000

0:015> !dumpobj 0x0e843368
Name: System.String
MethodTable: 790fa3e0
EEClass: 790fa340
Size: 52(0x34) bytes
 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: CustomEditingMenu
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
790fed1c  4000096        4         System.Int32  0 instance       18 m_arrayLength
790fed1c  4000097        8         System.Int32  0 instance       17 m_stringLength
790fbefc  4000098        c          System.Char  0 instance       43 m_firstChar
790fa3e0  4000099       10        System.String  0   shared   static Empty
    >> Domain:Value  000db050:790d6584 000fe470:790d6584 <<
79124670  400009a       14        System.Char[]  0   shared   static WhitespaceChars
    >> Domain:Value  000db050:01d61438 000fe470:01d65140 <<

By using the !dumpobj (or !dofor short) you can look at all the objects in memory...providing youcan find their memory address. Other useful commands include...

!dumpstackobjects  (shows all objects currently on the stack)
!printexception (!pe)
!dumpallexceptions (!dae)

Now we know the class & method we can look at the code using the command !u...

!u 0bd81a4b

0bd81a0e e9b2000000      jmp     0bd81ac5
0bd81a13 8b8d54ffffff    mov     ecx,dword ptr [ebp-0ACh]
0bd81a19 ba02000000      mov     edx,2
0bd81a1e ff150c7ee20b    call    dword ptr ds:[0BE27E0Ch]
0bd81a24 8bf0            mov     esi,eax
0bd81a26 89b540ffffff    mov     dword ptr [ebp-0C0h],esi
0bd81a2c 8b8d54ffffff    mov     ecx,dword ptr [ebp-0ACh]
0bd81a32 ba01000000      mov     edx,1
0bd81a37 ff150c7ee20b    call    dword ptr ds:[0BE27E0Ch]
0bd81a3d 8bf0            mov     esi,eax
0bd81a3f 89b53cffffff    mov     dword ptr [ebp-0C4h],esi
0bd81a45 8b8d3cffffff    mov     ecx,dword ptr [ebp-0C4h]
>>> 0bd81a4b 3909            cmp     dword ptr [ecx],ecx
0bd81a4d ff15a891b00a    call    dword ptr ds:[0AB091A8h]
0bd81a53 8bf0            mov     esi,eax
0bd81a55 8bce            mov     ecx,esi
0bd81a57 3909            cmp     dword ptr [ecx],ecx
0bd81a59 e8a24e2900      call    0c016900 (Microsoft.SharePoint.SPListItem.get_ListItems(), mdToken: 060035ef)

This is an abbreviated version, but you get the same IL as you do inVS.Net, actually its better as you get some method names. We can nowuse reflector as before to solve the problem.

Debug using a crash dump

Most of the time your not really going to be able to attach adebugger to a live server, but that still doesn't mean you can't debugexceptions in SharePoint. Microsoft provide a utility called ADPlus,which will create mini dumps of the exceptions within your SharePointapplication. These dumps can then be opened in WinDbg to look at thedump in exactly the same way as you would using WinDbg live.

 

ADPlus is a console application which attaches to the process andwaits for dumps to occur, taking a dump when they do. Once captured thedumps can be transferred back to your development machine diagnosed foras long as you want without tying up the live server. This isparticularly useful when your SharePoint site is being managed by ahosting company and you do not have RDP access to the live server. Youcan easily script the commands so a support engineer at the hostingprovider can create the dumps and email them to you.

Useful commands include

adplus -hang -pn w3wp.exe

and

adplus -crash -pn w3wp.exe

When debugging SharePoint I have only ever got -crash to give me anything useful, but I am sure -hang will be useful one day.

Note: By default you do not get a memory dump forfirst chance exceptions (because they can occur frequently), howeveradplus can be configured to do this (see http://support.microsoft.com/kb/q286350/). Not having a memory dump only means you can't see the contents of parameters & objects...you may not always need them.

More on ADPlus can be found within these articles...

http://blogs.msdn.com/tess/archive/2006/01/11/511773.aspx
http://support.microsoft.com/kb/q286350/
http://blogs.msdn.com/johan/archive/2007/01/11/how-to-install-windbg-and-get-your-first-memory-dump.aspx

Further Reading

The links below give you some things to do which can make your SharePoint debugging life easier.

A solution to "An unexpected error has occurred" in WSS v3
Using IISAPP to get the process ID of a SharePoint application
Test your SPSiteDataQuery parameters using Snippet Compiler
Anonymous SharePoint Publishing site forcing login
Make your SharePoint debugging experience a little less painful

Personally I have found If broken it is, fix it you shouldby Tess Ferrandez to be one of the most interesting blogs arounddebugging code and .Net in particular. I would recommend heading overthere if you ever need to track down a difficult problem, you will getsome good ideas and maybe a solution.

These are some links which I find useful when using WinDbg...

http://blogs.msdn.com/tess/archive/2006/05/18/601002.aspx
http://dotnetdebug.blogspot.com/2005/12/new-commands-in-net-20-sos-windbg.html
http://blogs.msdn.com/tess/archive/2006/10/13/asp-net-2-0-investigating-net-exceptions-with-windbg-compilation-and-load-exceptions.aspx

Hopefully this has given you some ideas as to how to approachdebugging your problem, I'm sure there are more, but these should giveyou a good start.

-Vince

posted @ 2010-02-04 13:44  彷徨......  阅读(352)  评论(0编辑  收藏  举报