I've released an update to Ookii.CommandLine, my library for parsing command line arguments for .Net.
This new version comes with nullable reference type support (for .Net 6+), a new helper to make parsing easier, more customizability, an easier way to make -Help
style arguments, and some bug fixes.
See the full list of changes here.
With the new helper method, you can now just do the following to parse the arguments and write errors and usage to the console if parsing failed:
var parsed = CommandLineParser.Parse<MyArguments>(args);
And if you want to customize parsing behavior, you can still do so with this method:
var options = new ParseOptions() { NameValueSeparator = '=' }; var parsed = CommandLineParser.Parse<MyArguments>(args, options);
Of course, existing code to parse arguments that manually creates an instance of CommandLineParser
will continue to work.
Check it out on NuGet or GitHub, or try it out online!
Also, the Visual Studio code snippets (which previously required manual installation) are now available on the Visual Studio marketplace.
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.
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.
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.
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.