Friday, May 23, 2008 10:21 AM brian-murphy-booth

Remote debugging ASP.NET applications using Visual Studio 2008

If you have recently upgraded a Visual Studio .NET 2003 ASP.NET application project or a Visual Studio 2005 Web Application project to a Visual Studio 2008 ASP.NET Web Application project you may have noticed the following popup. Needless to say this makes it a little more difficult to connect remotely to your project in order to run and debug it:

Unable to create the virtual directory. Could not find the server 'http://remoteMachine' on the local machine. Creating a virtual directory is only supported on the local IIS server.

At this point I can only guess as to why connecting to a remote web application project no longer seems to work. I do have a few guesses but I won't bother mentioning what they are because inevitably somebody will tell me my guesses are wrong. Instead I thought I would share with you a relatively simple way to get back to work and remotely debug anyway.

In a nutshell, to remotely debug we want to run two instances of Visual Studio. One will be the "debugger" instance, and the other will be the "editor/compiler" instance.

Here are the steps.

  1. Install the Visual Studio 2008 Remote Debugger on your remote machine. You can find the installation file in the Remote Debugger folder on your Visual Studio 2008 installation disk.
  2. Once you have the remote debugger installed, run Visual Studio 2008 Remote Debugger Configuration Wizard from the start menu of the remote machine.
  3. Choose Run the "Visual Studio 2008 Remote Debugger" service. You could try running individual instances of the debugger but you may run into user rights or permissions related issues. Personally I prefer easy versus difficult. Your choice though.
  4. Leave the service user as LocalSystem and leave the password blank then click Next.
  5. If you see a Configure the Windows Firewall for Debugging option, choose the available option to suit your needs then click Next then Finished.
  6. Next in order to prepare your old project to be opened with minimal problems, open your vbproj or csproj file in notepad and remove the "IISUrl" related settings then save the project file.
  7. Back on your local workstation, open Visual Studio 2008 then click File --> Open --> Project\Solution... and browse to the UNC path where the project or solution file resides.
    • Example: \\someserver\C$\inetpub\wwwroot\RemoveWebApp\myapp.csproj
    • Note: If you are not an administrator on the remote machine then you cannot use the adminitrative "C$" share. Instead you will need to ask the administrator to create a share for you.
    • Note: If you are not an administrator on the remote machine you will also need to ask the administrator to add you to the "Debugger Users" group.
  8. You can leave the Web settings for the project properties set to Use Visual Studio Development Server or Use IIS Web server. It does not matter since we aren't going to be launching the project that way. If you do choose to create a virtual directory you will to create it locally on your workstation of course to avoid the error mentioned above. This will actually create a virtual directory that points to the UNC path where your content lives.
  9. This first instance of Visual Studio will be used to edit source files and compile the application as necessary.
  10. From your local workstation, open a second instance of Visual Studio 2008 but do not open any projects.
  11. Click Tools --> Attach to process...
  12. Enter the appropriate remote server name in the Qualifier textbox then click the Refresh button near the bottom.
  13. Choose the correct remote process (aspnet_wp.exe or w3wp.exe for example) and click Attach
    • If there are multiple w3wp.exe processes running and you aren't sure which to pick you can run "cscript c:\Windows\System32\iisapp.vbs" on the remote machine to get the right PID. iisapp.vbs simply lists the running W3WP.exe processes along with their Application Pool name and PID.
    • If there are *no* processes running that you know you need to attach to, then you should make at least one request to http://someServer/RemoteWebApp" in order to spawn the worker process.
    • To make retrieving the PID a little easier I have included some sample VBS code below to get it for you.
  14. Click File --> Open --> File and open the source file that you want to debug from your UNC path.
    • Example: \\remotemachine\C$\inetpub/wwwroot\RemoveWebApp\Default.aspx.cs
  15. Set a breakpoint somewhere.
  16. This second instance of Visual Studio will be used to "debug" your project
  17. Open IE and request your page and you should break at the desired location.

NOTE: Something you might want to do to avoid the need to attach over and over while writing your code is to disable the idle timeout settings and possibly the recycling settings of the application pool that your ASP.NET application is using in IIS. To find which application pool your application is using you need to go to the remote server and open the IIS manager. Then go into your application's properties and look at either the "[Virtual] Directory" tab or "Home Directory" tab depending on whether it is a web site or directory level application.

To find the application pool name go into the properties of your application.

To disable the AppPool idle timeout go into the properties of the correct AppPool:

 

And finally... here is a script I wrote to make obtaining your remote PID a little easier. To use this:

  1. Copy/paste the text below into notepad
  2. Save the file with a VBS extension
  3. Edit the first 3 variables machineName, appPoolName, and url so they are correct for your remote server.
  4. Run this from your workstation.
''''''''''''''''''''''''''''''''
' Variables
machineName = "remoteMachineName"      'This to your remote machine.
appPoolName = "DefaultAppPool"  'This is the AppPool your ASP.NET is using.
url = "http://remoteMachineName/"       'This is the URL that will launch your AppPool

wmiPath = "winmgmts://" & machineName & "/root/cimv2"
wmiQuery = "SELECT * FROM Win32_Process WHERE Name='w3wp.exe'"

''''''''''''''''''''''''''''''''
' Code execution begins
Set wmiObj = GetObject(wmiPath)
Set wpList = wmiObj.ExecQuery(wmiQuery)

ShowAppPoolPid()

response = AskAboutRequestingPage()
If (response = vbYes) Then
	SpawnWorkerProcess()
	MsgBox "Unable to locate PID for '" & appPoolName & "'"
End If

''''''''''''''''''''''''''''''''
'Methods
Sub ShowAppPoolPid()
	message = ""
	For Each wp In wpList
		name = GetAppPoolId(wp.CommandLine)
		If (UCase(appPoolName) = UCase(name)) Then
			message = message & vbCrLf & "   " & wp.ProcessID
		End If
	Next
    
	If (message <> "") Then
		MsgBox "'" & appPoolName & "' is running under the following PID(s):" & message
		WScript.Quit()
	End If
End Sub

Function GetAppPoolId(strArg)
	Dim Submatches
	Dim strPoolId
	Dim re
	Dim Matches

    On Error Resume Next

	Set re = New RegExp
	re.Pattern = "-ap ""(.+)"""
	re.IgnoreCase = True
	Set Matches = re.Execute(strArg)
	Set SubMatches = Matches(0).Submatches
	strPoolId = Submatches(0)
	
	GetAppPoolId = strPoolId
End Function

Function AskAboutRequestingPage()
	message = "'" & appPoolName & "' is not currently running on '" & machineName & "'. Would you like to make a request to '" & url & "' in order to spawn the process?"
	style = vbYesNo + vbCritical + vbDefaultButton2
	title = "AppPool not running"
	AskAboutRequestingPage = MsgBox(message, style, title)
End Function

Sub SpawnWorkerProcess
	Dim ie: Set ie = WScript.CreateObject("InternetExplorer.Application", "Ie_")
	ie.Navigate url
	
	ie.Visible = True
	Set ie = Nothing
End Sub

Sub Ie_NavigateComplete2(ByVal pDisp, URL)
    ShowAppPoolPid()
End Sub 

Comments

# re: Remote debugging ASP.NET applications using Visual Studio 2008

Thursday, July 31, 2008 12:45 AM by Shailesh

Your script helped a lot with little changes. :)

Thanks.

# re: Remote debugging ASP.NET applications using Visual Studio 2008

Friday, November 7, 2008 4:43 PM by olivierH

Have to try this as soon as I get back to work.

I've spent hours figuring how to debug a remote asp.net website from a vista workstation editing with VS2008. Without luck. this could be my last change

Note: I run Remote Debugger on Windows Server 2008 (where IIS7 resides) as a service, but can't see no "debugger" group or user?

Furthermore, event if this solution works (which would be at least some solution), there must be a better way ??!!?? People at MS certainly figured out how it can/should be done ... since it seems quite a "natural" feature to remotely debug, at least on an isolated private local network ....

# re: Remote debugging ASP.NET applications using Visual Studio 2008

Friday, January 2, 2009 9:26 AM by brian-murphy-booth

Oliver,

Imagine if you created a feature in your application that was used by 1% of your users, but created 25% of your support calls. Imagine that there was nothing you could do to make your feature any easier to use in order to try to illiminate those support calls. You might be tempted to remove that feature. Microsoft occassionally runs into that sort of situation and I am *guessing* that this is one of those situations. Remote debugging has never been a solid solution for various reasons that I won't go into [so that you can't prove me wrong]. As a support engineer I am actually pretty happy that this feature is gone! To me at least, it makes sense that this feature has been removed.

# re: Remote debugging ASP.NET applications using Visual Studio 2008

Wednesday, March 31, 2010 10:52 AM by brian-murphy-booth

Shawn,

Visual Studio 2005/2008 is pretty forgiving when it comes to debugging managed code. As long as you are debugging an assembly built as "Debug" (not Release) so that Visual Studio can figure out filenames of original source code by using the PDB files (debug symbols), it will step through any CS file that you have open that matches the original source file name. It will even step through a source file that is the wrong one as long as the file name matches. So as long as the "local" CS file that you have open in VS is the correct one, you can debug assemblies that are loaded in the remote process.