Blog

.Net Configuration Section Documentation Generator

Today I'm releasing another small tool that I created for personal use that I believe others might find of use. The tool is the .Net Configuration Section Documentation Generator (more proof that I should not be put in charge of naming things), which does what it says on the tin: it generates documentation for configuration sections defined using .Net's ConfigurationSection class.

Basically, it can generate an XSD schema from a ConfigurationSection, to which you can then add annotations to document the elements and attributes of the section, and then generate an HTML documentation file from that schema. The tool can be used with Microsoft .Net and Mono.

As an example, check out the schema for the documentation generator's own configuration section as generated by the documentation generator, and with added annotations. And finally, the documentation file generated from the annotated schema. This is only a very trivial configuration section, but it gives you an idea of what the output of the documentation generator looks like.

More information and downloads here.

Categories: Software, Programming
Posted on: 2013-06-08 10:42 UTC. Show comments (1)

Creating a route for a .asmx Web Service with ASP.NET routing

While working on the update to my site (which is now completely finished), I came across a minor problem: I had an old ASP.NET Web Service (you know, the .asmx type, predating even WCF) that I needed to preserve at the same URL for compatibility purposes.

However, that URL was inside a folder on the old site. And in the new ASP.NET MVC site, that folder didn't exist anymore; instead, requests for that path were handled by an MVC Controller. This meant that it was not possible to leave the .asmx file at its original location, because an existing physical directory pre-empts the MVC route for the controller, so it would render all the other pages with the same base URL unviewable.

I figured I'd be able to use RouteCollection.MapPageRoute to redirect the old URL to the .asmx file's new location, but it turned out that this function only works for pages (.aspx files), as it requires that the HTTP handler for the route's target derives from System.Web.Page. Searching the web wasn't able to find a solution for this, but some investigation into the inner workings of ASP.NET routing let me devise my own solution, which I thought I'd share here.

The trick, it turns out, is to create a custom IRouteHandler, one that is able to return the correct IHttpHandler for web services. This turned out to be fairly simple:

using System;
using System.Web;
using System.Web.Routing;
using System.Web.Services.Protocols;

public class ServiceRouteHandler : IRouteHandler
{
    private readonly string _virtualPath;
    private readonly WebServiceHandlerFactory _handlerFactory = new WebServiceHandlerFactory();

    public ServiceRouteHandler(string virtualPath)
    {
        if( virtualPath == null )
            throw new ArgumentNullException("virtualPath");
        if( !virtualPath.StartsWith("~/") )
            throw new ArgumentException("Virtual path must start with ~/", "virtualPath");
        _virtualPath = virtualPath;
    }

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        // Note: can't pass requestContext.HttpContext as the first parameter because that's
        // type HttpContextBase, while GetHandler wants HttpContext.
        return _handlerFactory.GetHandler(HttpContext.Current, requestContext.HttpContext.Request.HttpMethod, _virtualPath, requestContext.HttpContext.Server.MapPath(_virtualPath));
    }
}

This route handler can then be used to add a route for a .asmx web service:

routes.Add("RouteName", new Route("path/to/your/service", new RouteValueDictionary() { { "controller", null }, { "action", null } }, new ServiceRouteHandler("~/actualservice.asmx")));

One important thing to note is the RouteValueDictionary values I'm passing to the route. If you don't add values for "controller" and "action" to the dictionary, the Html.ActionLink helper method will match this route for any controller or action, leading to completely incorrect URLs if this is the first matching route. Since you probably want to have this route before the MVC default route (which was the case for me), that would be a problem. Setting the values in the route value dictionary resolves this issue.

Of course, you can create your own extension method to make this easier:

public static Route MapServiceRoute(this RouteCollection routes, string routeName, string url, string virtualPath)
{
    if( routes == null )
        throw new ArgumentNullException("routes");
    Route route = new Route(url, new RouteValueDictionary() { { "controller", null }, { "action", null } }, new ServiceRouteHandler(virtualPath));
    routes.Add(routeName, route);
    return route;
}

Which means you can now simply use this:

routes.MapServiceRoute("RouteName", "path/to/your/service", "~/actualservice.asmx");

And voilà, I was now able to preserve the URL to my legacy web service without needing to have a physical file matching that URL. If you're faced with a similar situation, I hope this helps you.

Categories: Programming
Posted on: 2013-05-30 15:56 UTC. Show comments (4)

Welcome to the new Ookii.org

As you can see, Ookii.org has gotten a revamp. Now you may wonder, why make such a radical update to a site when the content doesn't change that often? The main reason is that I wanted to get my hands dirty with some modern web technology.

While web development has never been particularly important to me, it was something I knew how to do and I kept somewhat up-to-date with. This dates back to making the site for my high school (at the time in Frontpage). However, as I'd been busy with my Ph.D. in Japan, I had very little time to keep up to date with stuff I didn't have any need to use in my research. Now that I've finished and haven't started my new job yet, it was the ideal time to brush up a little.

Back when I started this site, I wrote it in ASP.NET 2.0. I hand-rolled an AJAX library, because jQuery was years from being invented and actually AJAX support in websites wasn't all that common yet. The AJAX parts of the site used web services that returned data in XML, because no one had thought to start using JSON yet either. "Mobile browsers" at the time meant IE for Windows Mobile, which didn't support script at all and was barely on par with IE6 on the desktop otherwise. And speaking of IE6, supporting that was still very much a priority at the time.

But things have changed, and the goal was to re-familiarize myself with the state of the art. So this site is written in ASP.NET MVC 4, using the Entity Framework for data access. On the client, it uses HTML5 and CSS3, with scripts utilizing jQuery and a few related libraries. The site now has a responsive layout thanks to Zurb Foundation (try it: resize your browser window and watch the layout change), which has the side-effect of making it much more friendly for mobile devices. I've also used Knockout.

I have to say I was surprised at how much web programming has changed. ASP.NET MVC is light-years beyond the old web forms. Not only are the frameworks much better and the HTML/CSS much cleaner (at least, as long as you only target modern browsers), the tooling (in the form of Visual Studio 2012 in my case) also has improved tremendously.

Besides just redesigning the layout, I've also made a new front page that de-emphasizes the blog a little (since I don't update it that often), and instead provides a few more useful links as well as news about my Let's Plays from the associated Twitter account.

Note that not everything uses the new layout. Currently, only the blog has been updated. I intend to move other sections of the site to the new layout over time.

Let me know what you think, or if you find something that's broken.

Categories: Site news, Programming
Posted on: 2013-05-07 19:50 UTC. Show comments (1)

Ookii.CommandLine 2.2

Yes, I realise this blog is all but dead. However, I will soon finally complete my Ph.D. at the University of Tokyo (so, yay me!), and as a result I can now finally release a few things that had been put on hold while I was writing my Ph.D. thesis. In addition, I will probably release a few projects related to my research that may hopefully be of interest to some people.

First up is a small update to Ookii.CommandLine. This update adds command line argument aliases, some updates for usage help generation, and code snippets to help with creating argument classes.

In addition, I used NuGet to create a symbols package and published it on SymbolSource, which you should apparently be able to use as a symbol server in Visual Studio without manually downloading the symbols.

Get the release from CodePlex or using NuGet.

Categories: Software, Programming
Posted on: 2013-02-06 12:11 UTC. Show comments (0)

Floppy support in Windows Virtual PC 7

Windows Virtual PC 7 is the successor to Virtual PC 2007, and the only version of Virtual PC that can run on Windows 7. It's freely available to anyone, and if you have Windows 7 Professional or Ultimate, you can also download Windows XP Mode, a virtual machine of Windows XP that allows you to run applications that may not otherwise work on Windows 7.

It seems however that Microsoft has removed the UI for using floppy disks with Windows Virtual PC 7. It was there in Virtual PC 2007, and now it's not. However, here's the thing: they only removed the UI, not the functionality itself.

The functionality for using floppy disks is still available in Windows Virtual PC 7, but it's only accessible via the COM object, which is not very convenient. Fortunately, Windows 7 also includes PowerShell, a very powerful shell scripting environment, that allows us to make things a bit easier.

Below, I present three PowerShell scripts: one to create virtual floppy disk images, one to attach floppy disks to a VM, and one to release them. The latter two can be used with both virtual floppy disk images, or a real floppy drive on the host computer.

You can download all three scripts here. Or you can just copy/paste them into a file, whichever you prefer. Note that you'll need to configure PowerShell to allow unsigned scripts to run, or sign the scripts.

Anyway, here are the scripts:

Create-VirtualFloppy.ps1:

param(
    [parameter(Position=0, Mandatory=$true)][string]$Path
)

$vpc = New-Object -ComObject "VirtualPC.Application"
if( -not [System.IO.Path]::IsPathRooted($Path) )
{
    # CreateFloppyDiskImage requires an absolute path
    [Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
    $Path = [System.IO.Path]::GetFullPath($Path)
}
$vpc.CreateFloppyDiskImage($Path, 2)

Attach-VirtualFloppy.ps1:

param(
  [parameter(Position=0, Mandatory=$true)][string]$VirtualMachineName,
  [parameter(Position=1, Mandatory=$true)][string]$FloppyPath,
  [parameter(Mandatory=$false)][Switch]$HostDrive
)

$vpc = New-Object -ComObject "VirtualPC.Application"
$vm = $vpc.FindVirtualMachine($VirtualMachineName)

if( $vm -eq $null )
{
    Write-Error "Virtual machine $vm not found."
}
else
{
    if( $HostDrive )
    {
        $vm.FloppyDrives.Item(1).AttachHostDrive($FloppyPath)
    }
    else
    {
        if( -not [System.IO.Path]::IsPathRooted($FloppyPath) )
        {
            # AttachImage requires an absolute path
            [Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
            $FloppyPath = [System.IO.Path]::GetFullPath($FloppyPath)
        }
        $vm.FloppyDrives.Item(1).AttachImage($FloppyPath)
    }
}

Release-VirtualFloppy.ps1:

param(
  [parameter(Position=0, Mandatory=$true)][string]$VirtualMachineName
)

$vpc = New-Object -ComObject "VirtualPC.Application"
$vm = $vpc.FindVirtualMachine($VirtualMachineName)

if( $vm -eq $null )
{
    Write-Error "Virtual machine not found."
}
else
{
    if( $vm.FloppyDrives.Item(1).ImageFile -ne $null )
    {
        $vm.FloppyDrives.Item(1).ReleaseImage()
    }
    elseif( $vm.FloppyDrives.Item(1).HostDriveLetter -ne $null )
    {
        $vm.FloppyDrives.Item(1).ReleaseHostDrive()
    }
    else
    {
        Write-Warning "No virtual floppy is attached to the virtual machine $VirtualMachineName."
    }
}

Using the scripts is pretty simple. Run PowerShell, navigate to the directory where you put the scripts, and invoke them. Remember that you need to enable execution of unsigned scripts (Set-ExecutionPolicy RemoteSigned), or sign the scripts.

The following example creates a virtual floppy drive image called sample.vfd, attaches it to the Windows XP Mode virtual machine, and then releases it again:

.\Create-VirtualFloppy.ps1 sample.vfd
.\Attach-VirtualFloppy.ps1 "Windows XP Mode" sample.vfd
.\Release-VirtualFloppy.ps1 "Windows XP Mode"

Please note that the virtual machine must be running for attach and release to work.

The following example attaches the host floppy drive A and then releases it again:

.\Attach-VirtualFloppy.ps1 "Windows XP Mode" A -HostDrive
.\Release-VirtualFloppy.ps1 "Windows XP Mode"

And that's it! Now you can use floppy disks with Windows Virtual PC 7 once again.

Categories: General computing
Posted on: 2010-10-17 06:20 UTC. Show comments (3)

Latest posts

Categories

Archive

Syndication

RSS Subscribe

;