Showing posts with label VS2005. Show all posts
Showing posts with label VS2005. Show all posts

Friday, March 6, 2009

Debugging InstallUtil.exe

The project I'm currently working on contains a Windows service with a number of performance counters. To run the code on a dev machine, we prefer to do so without first running an msi. So to get the performance counters installed, we tried to run installutil on the service executable. Which of course returned a vague error message and rolled back the changes. Fortunately, this type of problem wasn't too difficult to debug.

To demonstrate, I've created a new application and added a class that inherits from Installer. I've overridden the OnBeforeInstall event as follows:

protected override void OnBeforeInstall(IDictionary savedState)
{
    base.OnBeforeInstall(savedState);
 
    string nullString = null;
    int invalidLength = nullString.Length;
}

If I attempt to run "InstallUtil MyApp.exe" I receive the following within the console output:

An exception occurred in the OnBeforeInstall event handler of MyApp.MyAppInstaller.
System.NullReferenceException: Object reference not set to an instance of an object.


For trivial code such as my above sample, tracking down the problem should take most developers all of five minutes. Once you have a non-trivial amount of code (which was the case at work) you need a little more information. If I call "InstallUtil /ShowCallStack MyApp.exe" I receive the exact line where the problem occurs:

An exception occurred during the Install phase.
System.InvalidOperationException: An exception occurred in the OnBeforeInstall e
vent handler of MyApp.MyAppInstaller.
at System.Configuration.Install.Installer.Install(IDictionary stateSaver)
at System.Configuration.Install.Installer.Install(IDictionary stateSaver)
at System.Configuration.Install.AssemblyInstaller.Install(IDictionary savedState)
at System.Configuration.Install.Installer.Install(IDictionary stateSaver)
at System.Configuration.Install.TransactedInstaller.Install(IDictionary savedState)
The inner exception System.NullReferenceException was thrown with the following
error message: Object reference not set to an instance of an object..
at InstalUtilDebugging.MyAppInstaller.OnBeforeInstall(IDictionary savedState)
in C:\source\temp\InstalUtilDebugging\MyAppInstaller.cs:line 23
at System.Configuration.Install.Installer.Install(IDictionary stateSaver)


In many cases, this will be enough to solve the problem. There may be cases, however, where you need to attach a debugger to the process and step through the code to see where a problem actually started. To do this I add the following line to the beginning of OnBeforeInstall:

System.Diagnostics.Debugger.Launch();

After I recompile and again run InstallUtil, I am given a JIT Debugger dialog which allow me to attach to the process.


I select the instance of VisualStudio that has my install code and click 'Yes' to begin debugging. You may be given a warning stating "There is no source code available for the current location." Click 'OK' and press F10 once - this will show the Debugger.Launch statement as the current line of code being executed. From here debugging works as in any application.

Tuesday, February 17, 2009

Visual Studio installer projects - which project did I forget to include?

I made an interesting discovery while working on a project the other day. As I watched the compiler output from a particularly large solution I noticed several of the required assemblies were being built after the installer project. The reason was that someone forgot to add these assemblies to the installer. Normally this isn't hard to find and fix, but this particular solution has 150 projects, 149 of which need to be included in the installer. Manually comparing the list of installer dependencies to the list of projects takes quite a bit of time and is error-prone. Fortunately we can use the Project Dependencies screen to quickly find the missing items.

To illustrate, I've create a simple solution with five assembly projects and an installer project.


As I add each project to the installer, we see the primary output added within the installer


It looks simple enough when you only have a few projects. Add a couple dozen more and you can see that things are going to become more difficult.

To get a better view of the installer's dependencies, right-click on the solution in the Solution Explorer and choose "Properties." On the Property Pages dialog, choose Common Properties > Project Dependencies from the tree on the left. Under the Project dropdown on the right, select the installer project.

Here is my installer before adding any projects


After I add AssemblyA to the installer, the Project Dependencies looks like this


Notice the box beside AssemblyA now contains a checkbox. As I continue adding projects, each of these will be similarly checked. Below is an example after all but one assembly has been added. Even with 149 projects to include, it takes very little time to scan through the list and see which items remain unchecked.

Friday, December 12, 2008

Debugging XSL Transformations in VisualStudio 2005

I've been doing a bit of work lately with XSL transforms. While searching for a good transform debugging tool, I found that I had a decent one already installed - VisualStudio. To demonstrate, I pulled sample xml and xslt from the W3Schools site. (Click on each image to see a larger version.)


With the xsl template loaded in VS, right-click anywhere on the xslt and choose Properties. In the Properties window, set the Input value to point to the sample xml file (cdcatalog.xml in this case.)


At this point you can run the transform to view the output. Choose "XML" > "Debug XSLT" from the menu.


Nothing terribly interesting so far. The real fun doesn't start until you realize you can set breakpoints within the xslt. This is done the same as with other types of code files (by clicking the grey strip on the left or pressing F9.) Now, when you start the debugger, processing stops at the specified line. As expected, hovering the mouse over a variable or expression gives you a tooltip with the value.


Several of the other debug windows are also usable in this mode, such as the Locals and Immediate window.


Wednesday, August 27, 2008

Intellisense for WCF config files

I found it slightly irritating that there is no intellisense for WCF config files built into VS2005. Fortunately a quick Google search turned up a blog post with a solution. I figured I'd post it here so I can find it later. That, plus it allows me to meet my self-imposed quota of at least one blog entry per month :)

The solution can be found here.

Sunday, July 13, 2008

Don't make me GAC

We discovered an interesting "feature" in VisualStudio 2005 a couple days ago. Let's say I have a solution containing a Utilities project and a web site referencing that project. The Utilities assembly references a third-party dll (log4net in this case.) When the web site is compiled, it automatically pulls any dependent files into its 'bin' folder. Note the presence of log4net.dll


This seems fairly straightforward. But let's say I then load the solution on another computer (a build server perhaps.) The code compiles as before, but this time it doesn't pull in log4net.dll


At this point, I could manually copy the dll into the folder, right? That was my first thought, which of course proved to be wrong. The reason is that we also have an install project for the site. The installer is set to use all output files from the web project. If we add files to the site, the installer will automatically include them in the next compile. Unfortunately, when I manually add the dll to the bin folder, the installer overlooks it.

My next thought was to directly reference the log4net.dll in the web project.



Which still compiles on my box. And still ignores the dll on the build server. At this point, we opened up the references dialog on the build box. Much to our surprise, the dll is being referenced in the GAC


It seems that when a web project loads, it first looks in the GAC for referenced assemblies. If it finds them there, it ignores the files originally pointed to. Because of this, VisStudio doesn't copy the files to the bin folder. Which of course means the installer won't contain the dll.

Ideally, the dll shouldn't have been GAC'd on the build server. Since removing it from the GAC would cause us other issues, our workaround was to hard-code log4net.dll in the install project.

Note: The web site was built using the out-of-the-box project template, which doesn't create an actual .proj file. Microsoft later released a Web Application Project (with VS2005 SP1) that does create a .proj. It's possible that this would force the dll to load from the file reference, but I've not tested that theory.

Friday, May 2, 2008

Metadata? But the code's right there...

Here's a highly complex bit of code I've been working on


In this example I have a Customer class in MyAssembly2, which you can see is a separate project in the solution. On the main form of the application I'm making a call to the Customer instance method SaveToDatabase. If I right-click on the method call and choose "Go To Definition" I'm taken to a page of metadata.


This lets me see method signatures but not the code within those methods. If I were to try the same thing for my Utilities class, however, I'm taken to the .cs file within MyAssembly1. So what's the difference?

Here are the reference properties for the two assemblies:


The two are almost identical, but if you look closely, you'll see that MyAssembly2 has a "Specific Version" property where MyAssembly1 does not. This is because MyAssembly2 was added as a file reference - we pointed VisualStudio at the compiled dll instead of the project. Because of this, VS doesn't know that the dll and project are really one and the same.

The fix is a simple matter of deleting the reference to MyAssembly2 and re-adding - this time as a project reference.

Tuesday, April 29, 2008

Everyone should be good at something

Anyone who's worked with me in recent years knows how much I love deleting code. It could be removing something that's obsolete or refactoring to reduce duplication. Or maybe the requirements change mid-project. Needless to say, some question whether my SLOC (source lines of code) output is positive or negative.

Regardless, I stumbled upon a shortcut in VisualStudio (Shift + Del) that deletes the entire line where the cursor is located. No more selecting the whole line and then pressing Delete. I've become a code-deletion ninja!

Friday, March 14, 2008

Unlocking files when Visual Studio can't

There's an option in Visual Studio that, on compile, will pull all of your XML comments out into separate files. These can then be combined into a help file using a tool like Sandcastle. Most of the time this feature works correctly. If you cancel a build in process, or the compile fails, VS occasionally fails to release the file lock. From that point on, the compile fails with an error stating the file is in use by another process. I've not found a way within VS to force an unlock short of closing the app.

There is, however, a faster way using Process Explorer. Start Process Explorer and select Find > Find Handle or DLL... from the menu. Enter all or part of the filename currently locked, then click Search. You should see the guilty process - devenv.exe in this case.


Double-clicking on the entry will display a list of handles for that app, with the selected handle highlighted. Right-click on the selection and choose Close Handle. You'll see a dialog warning about potential crashes or system instability (meaning don't try this with a system file.) Tell it to continue and the handle will be closed. VS will again compile without issue.

Friday, December 28, 2007

Treat Warnings as Errors

In a previous post I mentioned the importance of fixing compiler warnings. I forgot about a useful project setting in Visual Studio that will cause all build warnings to display as errors instead. From the project's properties page, select the Build tab. Under "Treat warnings as errors," set the value to "All." While this may be difficult to justify on existing projects with hundreds of warnings, this is something that should be set on all new projects.





Tuesday, November 6, 2007

Invalid Data Source crashes Visual Studio

Binding data object to a WinForms control is usually straightforward. Say you have a ComboBox control. Clicking the triangle on the top-right will display the ComboBox Tasks dialog.


Once you check the box to "Use data bound items" you start by selecting the Data Source. Normally, clicking the Data Source dropdown provides you with a list of existing items, as well as the option to create a new one. A few days ago we ran into an issue where, instead of the datasources list, we were given this rather entertaining dialog


With a few hints from the blogging community, we were directed to the Data Sources window (Data > Show Data Sources, or Shift+Alt+D.)


Notice the first entry has an error icon. This is due to a datasource pointing to a non-existent class. Right-click the invalid entry and choose Remove Object. Now the Data Source dropdown behaves as expected.

Thursday, August 16, 2007

Custom Code Snippets

I'm not exactly sure when snippets were added to VisualStudio. I'm also not sure why I neglected them this long. I guess I just wasn't one of the Cool Kids. Hopefully I can make amends.

In case you are unfamiliar with snippets, this is the feature that lets you type 'prop' inside a class definition, press 'Tab' twice, and end up with a complete property definition. Even better, it highlights the items to modify, and you can easily Tab between them as you edit.


This is cool. Knowing this is there and using the built-in snippets, however, doesn't make one cool. True coolness occurs when one creates one's own. My journey began with an existing .snippet file. The path to these can be found in the Code Snippet Manager (under the Tools menu.) A few changes and I had the following:



<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>test</Title>
<Shortcut>test</Shortcut>
<Description>Code snippet for NUnit test</Description>
<Author>Pedro</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>testName</ID>
<ToolTip>Test name</ToolTip>
<Default>myUnitTest</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[[Test]
public void $testName$()
{
Assert.Fail("TODO: Implement test");$end$
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>


For those following along at home, save the above as a .snippet file. This can either be placed with the existing snippets, or in the "My Code Snippets" folder buried under "My Documents." Once saved, the Snippet Manager should list the new file.


To try it out, open up a .cs file containing unit tests. In a blank area between existing tests, type 'test' and press 'Tab' twice. Assuming I didn't screw up the above xml, you should now have the start of a new unit test.

Tuesday, July 17, 2007

Debugging with Exception Breakpoints

How many times has this happened to you? You're working on code that's not quite functioning correctly. You suspect there's an exception being thrown somewhere, but it's being caught and ignored. Maybe this was intentional, or maybe it was poorly written code. Either way, you need to locate the problem. Visual Studio 2005 has a handy little tool to help - Exception Breakpoints.

Say you have code that looks like this:



try
{
int a = 2;
int b = 0;
int c = a / b; // does not compute
}
catch
{
// Do nothing
}


If you were to run this code, you'd never know that there was a problem (well, not until you tried to use the value of 'c' elsewhere.) What we want to do is have the debugger break as soon as an exception is thrown. To do this, open the Exceptions dialog, either through the menu (Debug > Exceptions) or the keyboard shortcut (Ctrl+D followed by E).



Under the Thrown column, check the box next to the Common Language Runtime Exceptions. Now, when an exception is thrown, VS immediately breaks at the offending line of code. One word of warning - Depending on the size of the code, you may find far more exceptions being thrown than you had expected.

Tuesday, May 22, 2007

VS2005 Item Templates

I've been spending a lot of time lately coding unit tests. If I were writing tests for a class named Chainsaw, I would start with a blank class file, and modify til it looks something like this:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Pedro.PowerTools;
 
namespace Pedro.PowerTools.UnitTests
{
    [TestFixture]
    public class ChainsawUnitTests
    {
        ChainsawAdapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new ChainsawAdapter();
        }
    }
}

If you were to compare all of the TestFixtures in the assembly, you would find:
  1. For the most part, I have the same 'using' statements in each
  2. They all have the same namespace
  3. The class name for each TestFixture is the class to test, followed by "UnitTests"
  4. The data adapter name is the class to test, followed by "Adapter"

*Note - Yes, I'm testing several layers at once. Call it efficient. Call it lazy. It's simply my preference.

Though this isn't difficult to create by hand, there's an easier way - Item Templates. What I want is a way to right-click on my Project, choose Add > New Item, pick "MyUnitTests" from the list, and have it magically create the basic code. Turns out it's quite simple.

Start by placing the above code in a .cs file. Choose File > Export Template... from the menu. In the Choose Template Type screen, select "Item template" and the project where the .cs file exists.


Click Next. In the Select Item To Export screen, check the box beside the .cs file (ChainsawUnitTests.cs in my case.)


Click Next. Under Select Item References, check the box for nunit.framework. Ignore the warning.


Click Next. On the Select Template Options screen, enter the Template name and description. Make sure the box to "Display an explorer window..." is checked, and click Finish.


Once the template is generated, it will be placed in a .zip with the name of the template (for me, this is MyUnitTests.zip.) This is a decent start, but we need to modify a few things.

Open the .zip, and you should see the following files:
  • _TemplateIcon.ico
  • ChainsawUnitTests.cs
  • MyTemplate.vstemplate

Open MyTemplate.vstemplate. Near the end of the file, you should see the following <ProjectItem>

<ProjectItem SubType="Code" TargetFileName="$fileinputname$.cs" ReplaceParameters="true">ChainsawUnitTests.cs</ProjectItem>

In VS2005, when you choose to create a new item for a project, it asks for a filename. This filename, minus the extension, is placed in $fileinputname$. For this template, however, I want to type in the class to test, and have it generate a filename using the classname, followed by "UnitTests.cs". So let's change the line to

<ProjectItem SubType="Code" TargetFileName="$fileinputname$UnitTests.cs" ReplaceParameters="true">ChainsawUnitTests.cs</ProjectItem>

Save the file, and let's open ChainsawUnitTests.cs. It looks nearly identical to the original

namespace $rootnamespace$
{
    [TestFixture]
    public class $safeitemname$
    {
        ChainsawAdapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new ChainsawAdapter();
        }
    }
}

In fact, the only changes made were to the namespace and classname. Earlier, I mentioned wanting to type in the class to be tested, as opposed to the unit test class, when adding an item through the wizard. This is because I want to replace "Chainsaw" in each instance of "ChainsawAdapter" with the class I'm testing. As you may have already guessed, this comes from $fileinputname$. Two replacements and we have the following:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Pedro.PowerTools;
 
namespace $rootnamespace$
{
    [TestFixture]
    public class $safeitemname$
    {
        $fileinputname$Adapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new $fileinputname$Adapter();
        }
    }
}

Save the changes and re-zip the files. Drop the .zip in your custom ItemTemplates folder (the location can be found and/or modified in the VS Options dialog, under "Projects and Solutions" > "General." Having done all that, go back to the test project in VS. Right-click on the project and choose Add > New Item. In the Templates dialog, you should see your new template near the bottom of the dialog. Enter "DrillPress.cs" into the Name textbox and click Add.

Assuming all went well, VS should generate DrillPressUnitTests.cs with the following content:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
 
namespace test1
{
    [TestFixture]
    public class DrillPressUnitTests
    {
        DrillPressAdapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new DrillPressAdapter();
        }
    }
}