OdeToCode IC Logo

Building a New Mouse Trap II : Unzip

Saturday, November 26, 2005 by scott

In 1.1 we needed third party libraries to compress and uncompress data. In .NET 2.0 we have GZipStream and DeflateStream classes. However, as Stephen Toub points out in .NET matters, these classes are don’t handle the headers, footers, and other metadata of popular archive formats like gzip and zip.

In looking for the simplest possible solution to unzipping a single file in a windows forms application, I decided to interop with Shell32.dll. The disadvantage appears to be the inability to perform a “silent” operation – the shell always displays a modeless progress dialog no matter what flags are passed to the CopyHere method.  I tried to do some native interop debugging to figure out if the flags parameters was somehow getting munged in the interop boundary, but gave up. Part of my frustration was the disappearance of the Registers and Modules windows in the Visual Studio menus. I had to look up the shortcut keys to get to these commands. Apparently, this is a “feature” of the 2005 IDE that Paul Litwin also ran into.

The advantage to using Shell32 is the small amount of code required.

public class UnzipLogFileTransformer : ITransformer

{

    public string TransformFile(string inputFileName)

    {

        Check.IsRootedFileName(inputFileName, "inputFileName");      

        string destinationPath = Path.GetDirectoryName(inputFileName);

 

        string outputFileName = Unzip(inputFileName, destinationPath);

        File.Delete(inputFileName);

 

        return Path.Combine(destinationPath, outputFileName);

    }

 

    private string Unzip(string inputFileName, string destinationPath)

    {

        Shell shell = new ShellClass();

        Folder sourceFolder = shell.NameSpace(inputFileName);

        Folder destinationFolder = shell.NameSpace(destinationPath);

 

        Check.IsTrue(sourceFolder.Items().Count == 1,

            "Archive should contain only 1 item");

 

        string outputFileName = sourceFolder.Items().Item(0).Name;

        Check.IsNotNullOrEmpty(outputFileName, "outputFileName");

 

        destinationFolder.CopyHere(sourceFolder.Items(),

                                    OpFlags.TotallySilent);

 

        return outputFileName;

    }

}

Building New Mouse Traps Part I: FTP

Saturday, November 26, 2005 by scott

I’m using the holiday break to build yet-another IIS log file retrieval / parser / reporting tool with Visual Studio 2005. Sure, there are plenty of these around already, but not that use Windows Workflow and SQL Server 2005 XML data types. If nothing else, the project was an exercise in learning new areas in 2005 and 2.0.

The first task was to retrieve a list of available log files from an FTP server. The 2.0 framework provides FTP support with the WebClient and FtpWebRequest classes. The WebClient is useful if you want a quick DownloadData call to retrieve an array of bytes. When dealing with large files you might not want the result in a single array, but instead stream bytes to a file as the download progresses.

I used the FtpWebRequest class, which like it’s cousin the WebRequest class, provides a heavily abstracted (yet amazingly low-level) interface for FTP work. If you are expecting to find a method to retrieve detailed file information, you won’t. You have to parse the directory list text yourself (see adarsh’s blog for a sample).

I went with the FtpWebRequest class to have control over streaming bytes to disk and parsing the directory contents.

public void DownloadFile(string remoteName, string localName)

{

    Check.IsRootedDirectoryName(localName, "localName");

    Check.IsNotNullOrEmpty(remoteName, "remoteName");

 

    WebRequest ftp = BuildFtpWebRequest(new Uri(remoteName));

    ftp.Method = WebRequestMethods.Ftp.DownloadFile;

 

    using (WebResponse response = ftp.GetResponse())

    using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))

    using (BinaryWriter writer = new BinaryWriter(File.Open(localName, FileMode.Create)))

    {                                                             

        byte[] buffer = new byte[2048];

        int count = reader.Read(buffer, 0, buffer.Length);

        while (count != 0)

        {

            writer.Write(buffer, 0, count);

            count = reader.Read(buffer, 0, buffer.Length);

        }

    }

}

public List<string> GetFileNames(string remotePath)

{

    Check.IsNotNullOrEmpty(remotePath, "remotePath");

 

    List<string> result = new List<string>();

    WebRequest ftp = BuildFtpWebRequest(new Uri(remotePath));

    ftp.Method = WebRequestMethods.Ftp.ListDirectory;

 

    using (WebResponse response = ftp.GetResponse())

    using (StreamReader reader = new StreamReader(response.GetResponseStream()))

    {

        string line = reader.ReadLine();

        while (line != null)

        {

            result.Add(line);

            line = reader.ReadLine();

        }

    }

    return result;                       

}

 

 

protected virtual FtpWebRequest BuildFtpWebRequest(Uri uri)

{

    FtpWebRequest ftp = FtpWebRequest.Create(uri) as FtpWebRequest

        if (_credentials != null)

        {

            ftp.Credentials = _credentials;

        }           

    ftp.UseBinary = true;

 

    return ftp;

}

Design Patterns: A Love Story

Tuesday, November 22, 2005 by scott

Richard tilted his head to watch the waves push flotsam against the boat hull below. Up and down, the flotsam moved. Up and down.

Richard had an idea.

“Virginia, my dear”, he said to the blond woman beside him. “We’ve been singletons on this ship for a long time”.

“I know, Richard”, she replied. “My mean step-mother, the intercepting filter that she is, denies me time with others.”

Richard paused for a moment, to contemplate strategy. Her father, with his pipes and filters, would return soon, and force them to communicate over his message bus. He glanced aft, and saw no one else around. Richard turned his front controller to face Virginia, and looked her in the eyes. She was close now, and Richard could feel his active record rising.

“Virginia”, he whispered. “There is no observer in sight. Let us run below deck. I want to peel away your façade, and tightly couple.”

“Oh yes, Richard”, she blushed, and leaned towards him. “I want you to give me a dependency injection”.

[Author’s note: I’m sorry. I can’t continue. Shortly after typing the words “give me a dependency injection”, I was overcome by a sudden sickness and fell to the floor in convulsions. Let’s just assume the story has a happy ending, and forget this post ever happened. OK?]

Defining a Contract Is Hard

Friday, November 18, 2005 by scott

We often talk about interfaces defining contracts.

interface UserValidator

{

    bool ValidateUser(string username, string password);

}

The above interface seems simple. We can go to any object implementing the interface and invoke the ValidateUser method. Pass in a username and password, and the object will tell us if the user is valid.

Still, there is plenty left unspoken. Take the abstract base class MembershipProvider in ASP.NET. MembershipProvider includes an abstract ValidateUser method, just like the one in the interface defined above. Here are the remarks for the method:

Takes, as input, a user name and a password and verifies that the values match those in the data source. ValidateUser returns true for a successful user name and password match; otherwise, false.
For successful validations, ValidateUser updates the LastLoginDate for the specified user.

Now we know a little more about our “contract”. If we implement ValidateUser we should update the LastLoginDate during a successful validation. If software were really a science, I think we’d have some language construct to announce and enforce the LastLoginDate update.

There’s more though – if you look at the two available implementations of MembershipProvider in ASP.NET (SqlMembershipProvider and ActiveDirectoryMembershipProvider), they have another side-effect in common. Both classes increment performance counters and raise health monitoring events when users authenticate and fail to authenticate.

To the client who needs a method to validate a user, these events and perfcounters are inconsequential side effects. The events don't change the state of my object, or the provider. However, if I was a sysadmin who monitors failed authentication events, but can’t get the events to work when I plug in a custom build membership provider, I’d consider something broken.

A contract is a simple concept, but the devil still waits in the details.

Debug and Release Builds in ASP.NET 2.0

Tuesday, November 15, 2005 by scott

One of the adjustments to make when moving from ASP.NET 1.1 to 2.0 is how to produce debug and release builds.

1.1

In 1.1 we had the Build -> Configuration Manager menu option. This command launched a dialog box to let you choose from the available build configurations. Visual Studio provided Debug and Release configurations by default. The configuration selected in the Configuration Manager would tell Visual Studio how to compile the code-behind files. A successful compilation would produce a single assembly (.dll) in the bin directory, with a debugging symbol file (.pdb) appearing if the configuration asked for debugging symbols

Sometime later, the application would receive a web request and begin to execute. At this point, the ASP.NET runtime would generate code for the web forms and user controls in the application, then compile the generated code. The compilation at runtime would use the debug setting in the compilation section of web.config to determine if it should compile optimized code, or debug code (with symbols). ASP.NET would place the results underneath the Temporary ASP.NET Files directory. It is important to select the Release configuration in VS.NET 2003 and set debug=”false” in web.config to produce a true production build in 1.1.

2.0

Here is the most important concept to come to terms with in 2.0: Visual Studio 2005 knows nothing about compiling a web application. In 1.1 VS built the code-behind and ASP.NET built the web forms. In 2.0 Visual Studio 2005 delegates all compilation responsibilities to the ASP.NET platform.

With that in mind, there are two scenarios to talk about: building a web application without a Web Site Deployment project, and building a web application with the Web Site Deployment project. Let’s start with “without”.

When you ask Visual Studio to build a web project, nothing seems to happen. You don’t get the comforting feeling of having a bin directory with a .dll file inside. This is because ASP.NET, not Visual Studio, performs the build. ASP.NET builds everything, including .cs and .vb code files. ASP.NET places all the resulting assemblies in a folder underneath the Temporary ASP.NET files directory. You’ll see the results of the build if you poke around in the directory.

Because ASP.NET does all of the compilation, the debug setting in the compilation section of web.config controls debug or release mode. Compile with debug=”true” and you’ll find the .pdb debugging symbol files alongside each assembly.

This new compilation model makes the Configuration Manager for a web site obsolete. The only option appearing in a Visual Studio 2005 web site “project” is a Debug configuration. Don’t fret – it means nothing. The web.config file now rules the school.

When you are ready to deploy, you can publish the web site. The Publish command (Build -> Publish) will precompile a web application and place the results into a directory of your choosing. You can also publish to an IIS or FTP location. When you select the Publish command you’ll see a dialog box to choose a destination, and options for strong naming, fixed naming, etc. These options map directly to switches for the command line aspnet_compiler tool (see my article for more details). The aspnet_compiler tool also provides a switch to produce debugging symbols, but this option is not available from the Publish dialog. Publish will always precompile a release build without debugging symbols.

Note: the Publish command does not change the debug setting in web.config. The Publish command always compiles for “release”, however, if you precompile to an updateable web site, and then update the web site in place (which results in dynamic compilations), those dynamic compilations will produce debug code and pdb files.

The new Web Site Deployment (WSD) project changes the above scenario slightly. The WSD adds Release and Debug configurations to the Visual Studio 2005 configuration manger. This does not mean that Visual Studio knows how to compile a web site. Instead, Visual Studio knows how to use the MSBuild file provided by WSD to ask for Debug and Release builds. You can now select Debug or Release from the Configuration Manager in Visual Studio. The build request ultimately arrives at the same aspnet_compiler tool described above, and used by the Publish command.

Unlike the Publish command, a WSD Release build will change the debug setting of web.config to false. The WSD also defaults to placing release builds in a Release directory and debug builds in a Debug directory, which is familiar to anyone using .NET outside of web forms. WSD is an awesome tool and I'm sure will be covered in more detail here (eventually).

In conclusion, you control debug and release builds using the debug attribute of the compilation section in web.config – unless you are precompiling the website with the Publish command or the Web Site Deployment tool. The WSD will let you select Debug or Release builds, precompiles the site, and modifies web.config appropriately.

Writing Configuration Files

Monday, November 14, 2005 by scott

2.0 provides ability to modify configuration files. As you might expect, it is difficult to modify a configuration file in a locked down environment. As an example, the following code tries to change the compilation section to disable batch compilation and enable debugging.

protected void ModifyConfig_Click(object sender, EventArgs e)

{

    Configuration config;

    config = WebConfigurationManager.OpenWebConfiguration("~");

 

    CompilationSection compilation;

    compilation = config.GetSection("system.web/compilation")

       as CompilationSection;

 

    compilation.Batch = false;

    compilation.Debug = true;

 

    config.Save();             

}

Two problems you’ll quickly run into:

The code throws an exception under medium trust because the code needs read privileges on all of the configuration files from which it inherits settings. Medium trust only grants file IO permissions in the application’s virtual directory.

The code will need write access to the directory where the configuration file exists – not just write access to the file itself. If you watch the file system with a tool like FileMon, you’ll see the runtime create a brand new .config file with a temporary name. I imagine this approach prevents change notifications from recycling app domains too many times and let's the runtime "swap" in the new settings with a delete and rename operation.

SmartCHART for the Smartphone

Saturday, November 12, 2005 by scott

A few weeks ago, I took the dive into Smartphones and bought an unlocked MPX-220. Even though the phone isn’t the latest and greatest gadget that some lucky people have, I’m happier with this phone than any phone I’ve ever had.

My first late-night project with the 2005 RTM build is a Smartphone 2003 application to scrape traffic information from the state of Maryland’s Coordinated Highways Action Response Team site. Hint: (if anyone is listening) – I could have built the app in half the time if the information was available from a web service or RSS feed.

traffic incidents speed sensor readings

Nothing earth shattering here: source and executable.

I wanted to use generics. I couldn’t understand why the compiler didn’t like the namespaces and angle-ly brackets until I read the manual. Smartphone 2003 SE projects only target CF.NET 1.0, which does make sense, if you think about it. No generics. Also, every other project type only targets .NET 2.0. I tried to put unit tests into a separate class library, but there were problems and I ultimately ended with NUnit tests inside the main executable ( #ifdef’ed away).

Daniel Moth’s post “Invoke CF and Full Fx” assured me I wasn’t going crazy thinking asynch programming on the compact framework is hard when compared to asych-ing with the full framework. Some APIs are missing (Control.InvokeRequired), and others are mutated (Control.Invoke is crippled). I skipped the asynch thing for now.

The emulator is a tad sluggish. I needed to install ActiveSync 4.0 for Internet connectivity from the emulator. I decided to switch to a Virtual PC to avoid a developer preview version of ActiveSync from hosing my machine. The error message that appears when trying to configure network settings for the emulator points to this page. The directions on the page are hidden and confusing, but ultimately take you to the Visual Studio for Devices blog post “Virtual PC Network Driver”. The post contains some good instructions (but also 11 broken images). No driver is needed - just ActiveSync 4.0.

Two issues I haven’t resolved:

1) Visual Studio 2005 deploys the kitchen sink to the emulator on every run. Even pre-installed assemblies like System.dll get shoved into the emulator, which makes for long waits during debugging. I did some searching and found some information that indicates this scenario shouldn’t occur, but didn’t find a definitive solution.

Update: By moving from NUnit 2.2.0 to 2.2.3 (the version that officially supports 2.0), the deployment problem went away.

2) I’ve been unable to scroll the CF.NET ListView control one “page” at a time. I’ve set FocusedItem properties, SelectedItem properties, invoked Update, invoked Refresh – nothing seems to highlight a new item X items away and moves focus to the item.