I am going to talk today about the 'magic' that the debugger does to improve Web service debugging. The debugger has two features in this area:
I think these features have a certain amount of 'wow!'. Its pretty cool to give a demo of stepping into the web service without caring what computer/process the web service is implemented in.
Implementation of stepping:This feature works because the debugger has hooks into System.Web.Services.dll. The debugger gets four events for every web method call:
When a call leaves the client app, System.Web.Services checks if the application is running under a managed debugger. If so, it will try and load a component provided by VS (csm.dll) into the client application. It will tell csm.dll that a call is leaving the client app, and will also give the target machine. Csm.dll will then notify the attached debugger so that the attached debugger can try and prepare the destination machine. Lastly, csm.dll creates a memory blob and returns it to System.Web.Services. System.Web.Services will base64 encode this memory blob, and attach it as a custom header to the web method call. The memory is opaque to System.Web.Services, but it needs to contain a GUID to identify a logical thread that the call is apart of, a DWORD to describe which call within the logical thread we are at, and an identifier so that the remote machine can determine what debugger is attached to the client process.
When the call arrives at the server, ASP.NET will base64 decode the custom header. If the web service has debugging enabled ('debug=true' in web.config), it will then load up csm.dll into the ASP.NET process. This component is able to understand the opaque buffer. It will read the identifier of which debugger is attached to the client application, and contact that debugger.
When the debugger finds out that the call entered the server, it will then attach to the web server process. The debugger was also given the name of the function which is about to be executed. The debugger sets an invisible breakpoint on that function, and then continues execution of the web server. The web method will then be called, and the step will complete.
Logical callstackThe logical callstack displays the server's thread and the client's thread together in one big 'logical' callstack. Something like this:
Server Thread -------------------------------------- Client thread
To enable it, right click on the callstack window, and select 'Include calls to/from other threads'.
Implementation of the logical callstackWhen a call first leaves the client, it creates a GUID to represent the logical thread. When the call lands in the server, the server will remember this GUID. If the server happens to make a call into another server, this same GUID will be passed along. The debugger also remembers these GUIDs. It keeps state about where each logical thread is.
Limitations of this magic: