Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, July 18, 2011

Remote Debugging .NET Applications

From the past few days I have been stuck in resolving a bug which cropped up in one of my applications after it went to Production. The worst part was that it was a machine-specific issue and we couldn't reproduce it in any of our development systems. While trying to find a solution for this, I came across the concept of Remote Debugging.

Remote debugging is debugging a remotely running application through a development environment running on a system other than the one running the app. This is done by connecting the remote system to the system containing the development environment (in turn the debugger) through Sockets. Theoretically this is achieved in two steps -

  • The remote computer would open a socket and listen to debug instructions through it. These instructions are feed to the application that is being debugged and the application responds appropriately
  • The debugger would connect to the socket opened by the remote system and send instructions through it

Remote debugging can be used in many live situations. Examples include -

  • Debugging a machine specific issue which can't be reproduced on systems running the development environment (my exact requirement :))
  • Debugging applications which can run only on the server machine due to dependent third party libraries that cannot be used in the development machine

In this blog post, I will be focusing on Remote Debugging .NET applications through Visual Studio 2010. The screen shots correspond to a simple .NET application which would popup a MessageBox on a button click. Get the code here.

Configuring the Host Computer

The host computer is the computer containing the development environment. This is the system running Visual Studio 2010. To enable Remote Debugging, make sure the following ports are open on the host computer -

Ports
Protocol
Description
135
TCP
Required
500, 4500
UDP
Required if your domain policy requires network communication to be performed through IPSec

IPSec (Internet Protocol Security) is a protocol suite for securing IP communications authenticating and encrypting each IP packet of a communication session. Read more about IPSec here. However I am not going cover IPSec in this post.

You can check if the ports are open by using the telnet command at command prompt (telnet isn't installed by default on Windows 7. Install it from the "Turn Windows features on or off" section in the Control Panel).

Configuring the Remote Computer

To configure the remote system for debugging, either download and install the Microsoft Visual Studio 2010 Remote Debugger or copy the folder Remote Debugger from the Visual Studio install path, which is typically C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE. The Remote Debugger is available for three configurations - x86, x64 and ia64.

Visual Studio takes the .pdb files for debugging from the remote system for managed code. So copy the .pdb from the bin/Debug folder of the project to the remote system. Put this folder on share so that Visual Studio can access it later.

To enable Remote Debugging, make sure the following ports are open on the host computer -

Ports
Protocol
Description
135, 139, 445
TCP
Required
137, 138
UDP
Required
500, 4500
UDP
Required if your domain policy requires network communication to be performed through IPSec
80
TCP
Required for Web Server debugging

That's it; both the host and remote computers are up and ready for Remote Debugging.

Start the application on the remote system if it isn't running already. Also start the Visual Studio Remote Debugging Monitor on the remote system using the msvsmon.exe from the appropriate configuration folder in the Remote Debugger directory (The screenshot uses the x86 version).

Open the code in Visual Studio on the host system and select "Attach to Process". Typically Visual Studio identifies the .pdb file of the remote system if it can. If it doesn't, open the Modules screen from Debug -> Windows -> Modules. Check the Symbol Status of the .exe file which is being debugged and if it shows "Cannot find or open the PDB file" right-click on it and select "Load Symbols From" and specific the share path through the "Symbol Path".

Specify the breakpoints in the code and they would hit appropriately. There are two major bottlenecks in Remote Debugging -

  • The code from which the executable was built should be available at the time of debugging
  • The above mentioned ports should be open for debugging. Most of the developers wouldn't have administrative privileges on the client systems, so they would require people with sufficient privileges to open up these ports. However several organizations wouldn't prefer opening up ports for incoming connections

Before I conclude, here's an article from MSDN on how to Set Up Remote Debugging. Visit it if you would like a deeper insight into Remote Debugging.

Tuesday, March 22, 2011

Compiling Visual Basic, C# & F# Code Into A Single DLL Using msbuild

Recently I had a requirement in which a C# file had to be included in a VB.Net project. I knew I couldn't add the file directly to the project, so I cut over the C# file to VB.Net. At first this seemed pretty obvious since Visual Studio maps every project to a programming language and uses an appropriate compiler to compile the files in the project.

But giving it a deeper thought, I felt something didn't fit the picture. Every project, rather every file that we compile using the .NET Framework generates Common Intermediate Language which is used by the Common Language Runtime. It is because of this CIL that we have language interoperability in .NET. So theoretically speaking, code written in different languages should be able to exist in a single assembly.

Though I couldn't find a way to directly add a C# file into a VB.Net project, I found a way to create a DLL from compiled VB.Net and C# code through a concept of the .NET framework called Multi Module Assemblies.

In .NET, the minimum unit of deployment is an assembly; Dynamic Link Libraries (DLLs), Executables (.exe), etc. are all assemblies. An assembly can contain multiple files like resource files, the manifest, etc. It can contain files of another type called netmodules. A netmodule is a unit of compilation. It cannot be deployed directly but can be linked into an assembly. netmodules written in different .NET languages can be linked into a single assembly.

Unfortunately Visual Studio wasn't built for Multi Module Assemblies, hence there's no way to create a netmodule from a project in Visual Studio. However msbuild allows us to create a netmodule from the projects. There are typically three changes that have to be done to the .proj files (.fsproj, .vbproj, .csproj, etc.) for msbuild to generate a netmodule -

  1. Changing the OutputType to Module. Visual Studio doesn't recognize this output type, so even when you change this in the .proj files, Visual Studio won't be able to show it in the Project Properties
  2. Exclude the AssemblyInfo file from the project. netmodules aren't supposed to have an application manifest. If they do, the linker won't be able to resolve which application manifest should be used when we are building an assembly from multiple netmodules
  3. If one netmodule is dependent on another netmodule, a reference to the dependent module should be specified using the AddModules XML node in the .proj file. Similar to DLLs, netmodules cannot be circularly referenced

Once the .proj file has been modified, the project can be built using msbuild. If the project is a part of a solution, building the solution will create a netmodule for this project - msbuild solution_path

Once the netmodules are created using msbuild, a DLL can be created from them using the Assembly Linker of the .NET framework - al /t:library /out:"path_to_dll" path_to_netmodules

With this we have a DLL which contains all the netmodules bundled into one. To understand this better, let's consider an example - I have three projects, one in F#, VB.Net and in C# under a solution called MultiLanguage.

The .fsproj, .vbproj and .csproj have to be changed as mentioned above. From the netmodules obtained from msbuild, the DLL can be created using the assembly linker.

The sample solution and the build script can be downloaded from here. I automated the .proj changes using Microsoft's Build Engine API. You can give it a try here; it takes the .sln file as an input and modifies all the projects in the solution to generated netmodules.