Feel like a geek and get yourself Ema Personal Wiki for Android and Windows

21 December 2009

Todo lists should be fun if you want to stick to it

Since a few years I use David Allen's Getting Things Done system for organizing "stuff". Stuff includes todo lists, project materials, things on your mind, things to keep track of, etc.

One of the statements in the David Allen book is that you should use a system that you find fun to use, because that will make it easier to stick to it. To me, it is always fun to try out new things, and abandon old stuff in favor of new software.

My way to stick to my GTD lists is that I once in a while change the system with which I keep track of the lists. To find a new, shiny peace of software, keeps me interested in using the lists, which is of vital importance for the success of your GTD system.

Systems I have used so far:
  • The todo application and memos of my Palm Tungsten T3
  • Microsoft Outlook in combination with a HP ipaq 214. (Note: I found this setup extremely inconvenient. In my opinion, Outlook Mobile is not a user-friendly application.)
  • AbstractSpoon hierarchical todolist 
  • Home-made GTD tracking software. This worked for a while, but wasn't really a good idea in the long run since you have to solve issues and create additional features all by yourself ;)
  • Remember The Milk
  • Evernote
  • bLADE wiki. It is a personal wiki that works on Windows Mobile and on my desktop. It has no built-in support for GTD because it is a plain wiki. But if you take some time to arrange things the way you like it best, it is a very pleasant system to work with. At least I am very pleased so far. And my wife is too.
  • [Update] Because I bought an HTC Desire Android device lately, I created my own Personal Wiki for Android which I'm using now. 
Apart from the HUGE advantage that the switching gives me by keeping me interested, the other advantage is that it forces me to copy all the data from one system to another. This is a pleasant way to purge items and go over all of the lists in all of the corners of the system.

(The image is a GTD wallpaper from http://anabubula.com/)

12 November 2009

Filezilla and the trash

Filezilla took a lot of time lately after I gave the command to delete a local file or directory. Like ten seconds before the file or directory was deleted. That is really unacceptably slow, so I fired up sysinternals procmon to see what was happening.

Filezilla turned out to be browsing through my trash stuff before deleting the file which I requested to be deleted. There were really a lot of items in the trash, so it is obvious why Filezilla became so slow. I emptied the trash and Filezilla was happy again.

Less obvious is: why is Filezilla browsing through my trashed items? Or is it a system "feature" for which Filezilla cannot be blamed?

04 November 2009

One of the advantage of open source libraries

Today I once again experienced one of the great advantages of using open source libraries over using its closed source equivalents.

For our core library, we make use of several open source components, Nini being one of them. In our case Nini is used to read and write INI files.

Recently we discovered that a problem in one of our product had to do with this library. The library simply "ate" characters behind a double quote if the double quote was part of the setting.
[Blocks]
Block1 = Something, "Some caption", 1
The output would be:
Assert.AreEqual("Something, ", getValue("/Blocks/Block1"));
After discovering the Nini library was the cause, we decided we should investigate if we could solve the problem ourselves by creating a patch, since the library is open source. So we downloaded the code and opened it in Visual Studio. After some browsing through the code however, we quickly found a workaround: set the ConsumeAllKeyText property true on the IniReader instance.

With a closed source library, problems like this are as likely to occur as with open source products. The huge advantage of using open source in this case is obvious. If you're using a closed source product, you can only hope and pray for support in case of problems. With open source libraries, you can take things into your own hand.

30 October 2009

Git: my personal MS SQL server data time machine

I had to solve a bug that was caused by inconsistent state, persisted in MS SQL server. The bug could be reproduced. But it did cost some effort and you had to start over again once the bug had manifested itself to reproduce it again.

Git to the rescue. The solution was simple: with a few git commands, I created my own MS SQL server time machine. I added the raw SQL data to a Git repository, and now I can not only go back and forward, but I can also create branches, to mimic specific situations. I can now reproduce the bug, do my analysis, revert, reproduce again, etc. Very nice!

Here's a description of how to do this.
  • Stop sql server (via SQL management studio or using services.msc)
  • Go to C:\program files\Microsoft SQL Server\MSSQL.1
  • Right-click on the folder "MSSQL" and choose "git bash here"
  • git init
  • git add .
  • git commit -a
  • Enter a nice comment (with vi: press i, enter your comment, press escape, press :wq)
  • Create a branch for the data that is needed for this bug and switch to this branch: git checkout -b newbranchname. In my case: git checkout -b bug-1577
  • Start sql server again
Now I made the changes to get to the situation where I could reproduce the bug. To save this state, do the following.
  • Stop sql server
  • Go back to the git bash on C:\program files\Microsoft SQL Server\MSSQL.1\MSSQL
  • git status if you are a control freak (or just curious)
  • git add . if you like the newly added logs and traces
  • git commit -a with appropriate comment
  • Restart sql server
Now you can go ahead and test the data or bug. If you want to restore the situation, just do the following:
  • Stop sql server
  • git checkout -f = undo all local modifications
  • Start sql server
These last steps can be automated with a simple batch file:
net stop mssqlserver
git checkout -f
net start mssqlserver
There is a downside. It costs a lot of diskspace because SQL server seems to change each and every database every time. So each commit will add the entire data directory to git again. You can avoid this by comitting only invidual files. But, on the other hand, your time is probably more costly than disk space.

Once you get to know Git, you can't do without it any more.

13 October 2009

Map a checkbox to an action parameter in ASP.NET MVC

Mapping a checkbox to an action parameter in ASP.NET MVC is not trivial. At least I did not find trivial solution.

To get it working, use the following code:

<input type="checkbox" name="SomeName" id="SomeName"/>
<script type="text/javascript">
  $('#SomeName').click(function() {
    $(this).attr('value', $(this).attr('checked'));
  });
</script>

08 October 2009

Checked propertynames in NHibernate queries

Automatic renaming of a property in VS2008 won't refactor the propertynames in NHibernate config files and queries. You will find out after running the unittests, of course, but I'd rather have a compile error, or, better, have VS2008 refactor the NHibernate config and queries too.

For the NHibernate config the reasonable alternative is to use Fluent NHibernate, which uses lambda's to get the propertynames.

For the queries you have to write such a solution yourself.

I have a base class for all entities that looks like this

public Entity<T> where T : Entity<T>
{
  public static string PropertyName(Expression<Func<T, object>> e)
  {
    UnaryExpression ue = e.Body as UnaryExpression;
    MemberExpression me = (ue == null ? e.Body as MemberExpression : 
      ue.Operand as MemberExpression);
    return me.Member.Name;
  }
}
After that I can use this method to get the propertynames in queries:
Criteria.Add(Expression.Eq(
  User.PropertyName(x => x.Emailaddress), "email@example.com"));
There are disadvantages. First, using Lambda expressions is slower than using the string value. Second, this only works for public properties. Third: in VB this will look very ugly. Until now, I can live with these disadvantages.

29 September 2009

Inheritance and NHibernate.Search

I recently ran into a problem using NHibernate.Search. It is not possible to query properties of a derived class if NHibernate.Search only has access to it through a base class.
I used to have:
  [IndexedEmbedded]
  public virtual FieldType FieldType
  {
      get;
      set;
  }
The FieldType class is an abstract class from which concrete implementations derive. I wanted to index the properties of several derived classes, for example the OtherFieldType class:
public class OtherFieldType : FieldType {
  [Field]
  public virtual string Name {
      get;
      set;
  }
}
In this example, querying NHibernate.Search with "FieldType.Name:something" won't return any results. Apparently NHibernate.Search does not know it should query the concrete class implementation, OtherFieldType, for this query.

The workaround for this is to remove the IndexedEmbedded attribute from the base property and include a private field dedicated for NHibernate.Search to index and query. The private field does hold the concrete implementation:
  public virtual FieldType FieldType
  {
      get;
      set;
  }

  [IndexedEmbedded]
  private OtherFieldType OtherFieldType
  {
      get
      {
          return FieldType as OtherFieldType;
      }
  }
In this way, NHibernate.Search will know how to index and search the embedded properties. The query "OtherFieldType.Name:something" will now return the correct results.

26 September 2009

Google Chrome plugin for IE - yet another browser platform

The newly released Google Chrome plugin for IE introduces yet another browser platform to be aware of as web developer. We test our websites on IE, FF, Chrome and maybe Safari. Now a new platform is added to the list: IE with a bit of Chrome.

The Google Chrome Frame developers did their best to make it as unobtrusive as possible. The plugin will only kick in if the Google Chrome Frame tag is present on a webpage. But the tag does not guarantee anything. Maybe the website visitor refuses to install the plugin. Maybe the website visitor uses the opt-in list to force your website to use the plugin, although there is no tag present.

So note to self: don't forget to test the website without the plugin if the Google Chrome Frame tag is used. And don't forget to test the website with the plugin enabled although the website does not include the tag.

25 September 2009

Html Agility Pack to the rescue

One of our products is a messaging processor which uses XMl internally. Somehow someone messed up and managed to insert characters into the XML which are not valid, making the message "invalid XML". By the way "Invalid XML" is a contradictio in terminis. I would rather refer to "invalid XML file" as A Text File That Looks A Lot Like XML But Isn't.

Solving the issue would require updating the shared core component which is used by many applications. Updating the core component was not an option as a bugfix.

We decided to fix the bug in the following major release, but still needed a workaround for the problems in the field.

Enter Html Agility Pack. It is a tolerant library that can read HTML files (text files looking a lot like SGML or like XML) and convert them to XHTML. We inserted a processor into the processing chain that XMLlifies the message as it passes the processor, et voilĂ !

24 September 2009

Another client wish

For an internal project (C# / NHibernate / ASP.NET MVC / JQuery) there was a request that users could be able to mark parts of the data with colors to indicate parts of the data have changed.

If I had to incorporate this into my domain model, it would be quite complex. I would have to keep track of statuses of every property of every object, and every action should know which status data is relevant to that particular action.

I decided that this would be a simple solution: the coloring will be purely a user-interface feature. There will be a table in the database with the columns "URL", "ElementId", "Color" to store the coloring data. The userinterface will be querying this data after the page has been loaded and store the data using AJAX calls.

I am not 100% sure about this. It is clearly the simplest solution. But the colors are really statusinfo about the data in the application, while the statusinfo will never be associated with the data, only with user interface elements. But I decided in favor of the UI solution taking into account that
- the coloring data is cursory
- the request is purely a visual one
- the ASP.NET MVC application will be the only user of the data

See if I will regret this later.

23 September 2009

Client wishes

In an application I am working on different clients want different views, depending on the context. For example: client A is a sonographer and wants all ultrasound data on top, client B is an obstetrician and wants all obstetric data on top.

I first thought of a per-user preference which is stored in the database. Unfortunately, I did not have a per-user store mechanism yet, so I would have to develop it. Because I am lazy, this triggered a though: this isn't actually a per-user setting, but a per-role setting. There are clients that are both obstetricians and sonographers. They would want the data ordered differently depending on the role they have at that time.

So I decided to solve this in a very simple way, which the user is going to like. I created a button in the view that only switches view properties when clicked. No server-side code involved. It sets a persistent cookie on the client with the last state. The next time the user visits the particular part of the application, the last state is restored.

22 September 2009

"convenience" back doors

It can be tempting to create "convenience back doors" in code to make short cuts. "Isn't it easier to skip all these layers and just call layer 1 from layer 3?". Yes, it is easier in the short run, but later on it will make refactoring very hard. I think the word "just" in any code-related conversation should set off alarms in your head. Layers are there for a reason.

I am currently involved in replacing a DAL for an existing legacy application. The existing DAL creates SQL statements and passes them to a handler that executes the statements with a connection from a connection pool. My job is to remove the SQL statements and replace them by service calls. Luckily the statements are very simple, because the application once used DBase, which isn't a relational database. So most of the SQL statements don't even use joins. This is of course very inefficient, but in this case my luck.

I started bottom-up, so I abstracted the SQL handler first to be able to monitor what is going through. Secondly i started looking for calls to the SQL handler class. It is a Vb6 application, but there is actually a layered architecture, so I figured that too wouldn't be too hard.

Until i found a function in the application layer. The function was there for "convenience". With the function anyone can throw any SQL statement at the SQL handler. And did i mention ... the function is part of the COM component's public interface.

The point of making classes and functions or, more generally, layers, is to abstract implementation details away from its users.

So much for abstraction.

17 September 2009

Fetchmode.Eager, but still a proxy

I just had an issue where i could not cast a property of type Proxy_blah_blah_blah to the type that it really should have been ("Patient", in this case). The issue was still there after i explicitly set the fetchmode to "Eager": NHibernate seemed to ignore the fetchmode.

In a way, it actually did ignore the fetchmode. I am not sure if this is by design. I did not look this up, but blog the cause for future reference.

The problem was that the objects which were to be loaded eagerly, were already fetched by a previous query which had fetchmode lazy for these objects. So the objects were already present in the current session as proxies. Apparently NHibernate does not re-evaluate the lazyness of the objects if another query wants these objects to be fetched eagerly. I can understand this, because it is impossible to change existing objects to another type + nhibernate obviously wants to return the same objects from the same session.

To summerize the problem:

1. a query loads objects which have a reference to Patient which has a lazy initialized property Person
2. The property Person is now a proxy, in my case the proxy of a base class of Person
3. a second query loads objects that also have a reference to Patient. The query has fetchmodes for associationpath 'Patient' = Fetchmode.Eager and for associationpath 'Patient.Person' = Fetchmode.Eager.
4. Nhibernate now in a way ignores the fetchmode properties: in nhprof the query looks good, but the returned object tree has the previously created proxy objects instead of the resolved objects.
5. Using the Person property as a Person object now fails, because it is a proxy of a base class of Person.

A solution would be to use multiple sessions. The solution i chose in this setup is to eagerly load the objects in the first query, which made sense anyway.

01 September 2009

Throw it away liberally

The code we developers write is like a child. It shouldn't be. The problem with being protective about your own code is that there is a barrier to change it. But the code is bad, contains lots of bugs, or worse, does not fulfill any requirement that it should.

That's why we should be very liberal to throw away code if we need to, especially if it is our own code.

Sourcegear does not add files after having worked online

If you're using the Sourcegear Vault client plugin for Visual Studio and use the feature "work offline", you have probably encountered this problem. If you added file while being offline, the added files won't be added to Vault after you "Go Online". The vault client thus silently corrupts your codebase.

I learned the hard way that i have to open each and every folder where i could possibly have added new files, to manually add them to vault after going online. But lately I discovered a good workaround. You can right-click on the project file, and choose "Add to vault" on the project root. All files that have not been added yet, will be added by that action.

How to get a working Back-button for an AJAX app in Internet Explorer

In an AJAX application, the back-button will take you to the wrong place because in AJAX applications the actions don't update the browser location. There are some solutions that change the hash of the Location (the part behind the #), but those solutions do not work in Internet Explorer.

The problem with IE is that a change in the hash will not lead to an entry in the history, so the back button will take you back to the previous page anyway. IE does react if you change the src attribute of an IFRAME, so most solutions for IE are in the direction of using a hidden IFRAME.

Since I did not find any actually working code, I post it here for future reference. The code works in IE, FF and Chrome.

The main page contains an iframe. The source of the iframe is an actual document on the server (iframe.html). The only thing the iframe document does is echo it's source url back into the parent page location hash:
<html>
 <body>
  <script type="text/javascript">
   function parseLocation() {
    var src = location.href;
    var pos = src.indexOf('href=');
    if (pos === -1)
     src = '' //home
    else
     src = src.substring(pos + 5);
    top.location.href = top.location.pathname + '#' + src;
   }

   parseLocation();
  </script>
 </body>
</html>

The parent page redirects anchor clicks to update the src attribute of the iframe. Because the iframe will be reloaded, IE will update the history of the browser. The iframe writes the src url back into the parent page location. The parent page monitors the location and loads the appropriate url in the appropriate div:
<html>
  <head>
    <title>Ajax test</title>
  </head>
  <body>
    <script type="text/javascript" 
      src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
    </script>
    <script type="text/javascript">
      var baseHref = location.protocol + '//' + location.host;
      
      $(document).ready(function() {
        createAjaxLinks();
        setInterval(checkLocationHash, 50);

        $('#trackingframe').get(0).src = iframeSrc + '?href='
          + location.hash.substring(1);
      });
      
      function createAjaxLinks() {
        $('a.' + ajaxLinkClass)
          .removeClass(ajaxLinkClass)
          .click(function(){
            var href = this.href;
            if (href.indexOf(baseHref) > -1)
              href = href.slice(baseHref.length);

            $('#trackingframe').get(0).src = iframeSrc 
              + '?href=' + href;
            return false;
          });
      }
      
      function checkLocationHash() {
        if (location.hash !== this.lastHash) {
          var url = null;
          if (location.hash === '' || location.hash === '#') { 
            //home
            url = initialDocument;
          }
          else {
            var url = location.hash.substring(1);
          }
          if (url !== null) {
            url = baseHref + url;
             $('#siteContainer').load(url, null, createAjaxLinks);
          }
          this.lastHash = location.hash;
        }
      }
      
      var initialDocument = '/1.html'; //absolute url
      var iframeSrc = '/iframe.html';  //absolute url
      var ajaxLinkClass = 'ajaxLink';  //class for ajax links
    </script>
  
    <div id="siteContainer">
    </div>
    <iframe id="trackingframe" style="display:none">
    </iframe>
    
  </body>
</html>
For this example I created three test documents, named 1.html, 2.html and 3.html, which will in turn be loaded in the siteContainer div.

1.html:
<a href="2.html" class="ajaxLink">Load the second document</a>

2.html:
<div>
 This is the second document. 
 <a href="3.html" class="ajaxLink">Load the third</a>
</div>

3.html:
<div>Third document</div>

This example loads all links with class "ajaxLink" into the "siteContainer" div. In real life, you would probably want more control over in which div the link will be loaded. This can be accomplished by including the "target" in the class somehow and parse the class of the link to find this target.

31 August 2009

Fixing the unit tests

In most of the cases, a failing unit test in my projects is a bug in the test and not a bug in the code it tests. It bring into question wether the unittests are worth the effort.

The answer is: YES. The unit tests are worth the effort. Once you created them:
  • You know how the code should be used: the unit test is your documentation
  • you will get a trigger if you change something for another usecase and break the code's original intent because the test will fail after that
  • The alternative is testing the code by starting the application itself, clicking to the right place, and testing the different scenario's. This is a very dull and time-consuming way of testing, and not very thorough. Creating a unit test for testing the code is way faster than the alternative, and the test will behave exactly the same each time you start it.

28 August 2009

Wrapping the NHibernate fetchmode

Configuring the NHibernate fetchmode and lazy/eager loading has two purposes: query efficiency (reduce database hits wherever possible) and preventing the dreaded LazyInitializationException. Most properties are configured for lazy loading, because this is a sensible default. This means you often have to tweak the fetchmode for particular queries in a particular way.

But combining queries and different fetchmodes scenario's will lead to a cartesian product of possibilities if used in a traditional, repository-like way.

For example:
  • IList<Author> GetAuthors()
  • IList<Author> GetAuthorsWithArticles()
  • IList<Author> GetAuthorsWithBooks()
  • IList<Author> GetAuthorsWithBooksAndArticles()
  • IList<Author> GetAuthorsByLastname(string lastname)
  • IList<Author> GetAuthorsByLastnameWithBooks(string lastname)
  • etc...

This looks like a bad design.

The solution is the Query Object pattern (here and here). This pattern wraps queries in objects.

If the query is an object, and the fetchmode can also be configured in an object-oriented way, applying fetchprofiles to a query and executing the query looks like this:
// .. get session and transaction somewhere ..

var results = 
  new AuthorsByNameQuery()
    .LastName("Adams")
    .WithBooks()
    .WithArticles()
      .List(session);

The query object wraps the criteria and fetchmode:
class AuthorsByNameQuery 
{
  internal DetachedCriteria Criteria;

  public AuthorsByNameQuery()
  {
    Criteria = DetachedCriteria.For<Author>();
  }

  public IList<Author> List(ISession session)
  {
    return Criteria
      .GetExecutableCriteria(session)
      .List<Author>();
  }

  public AuthorsByNameQuery Lastname(string lastname)
  {
    Criteria.Add(Expression.Eq("Lastname", lastname));
    return this;
  }

  public AuthorsByNameQuery WithBooks()
  {
    Criteria.SetFetchMode("Books", FetchMode.Select);
    return this;
  }
  public AuthorsByNameQuery WithArticles()
  {
    Criteria.SetFetchMode("Articles", FetchMode.Select);
    return this;
  }
}

I have been using queries and fetchprofiles this way in a few projects now and it really helps to structure the possibilities.

23 August 2009

Chaining ASP.NET MVC actions

Action Chaining is using the output of action A as input for action B. Applying this pattern to ASP.NET MVC projects is not trivial. This post is meant as a quick start.

Suppose you have the following scenario
  • client places order in browser

  • system redirects client to ~/Order/ThankYou

  • system sends email to client with summary about order

  • system shows summary of order to client
To accomplish this, it would be convenient to reuse ~/Order/Summary for both the email and the browser page


There are other usecases in which Action Chaining would be a valid pattern, for example in cases where you want to show the output of one action as PDF or as HTML depending on the required format. Apache Cocoon is based on this pattern.

The way to execute an action and capture the output in ASP.NET MVC involves some hijacking of the Response Stream and the RouteValues.

The Response Stream can messed with using a ResponseFilter. A response filter is a class that inherits from stream and takes a stream as constructor argument. The stream in the constructor is the original Response stream (or another filter, they can be chained). If you set the filter, the filter stream gets the writes and is supposed to pass the writes to the wrapped stream. Which is exactly what we won't do: we jealously keep the bytes to ourselves in a memorystream:
class BufferingMemoryStreamFilter : MemoryStream
{
public BufferingMemoryStreamFilter(Stream wrappedStream)
{
// ignore the wrapped stream
}
}
Controllers react on the routevalues to find the right action and view. Because we will be executing another action (perhaps on another controller also), the routevalues should be changed for the occasion and restored afterwards.

The method that execute and capture an arbitrary action on an arbitrary controller is posted below.
string GetActionOutput(string controller, string action)
{
// hijack the response stream
var orgResponseFilter = HttpContext.Response.Filter;
var memoryStreamFilter = new BufferingMemoryStreamFilter(
HttpContext.Response.Filter);
HttpContext.Response.Filter = memoryStreamFilter;

// hijack routeData
var routeData = ControllerContext.RequestContext.RouteData;
var orgAction = routeData.Values["action"];
var orgController = routeData.Values["controller"];
routeData.Values["action"] = action;
routeData.Values["controller"] = controller;

var c = ControllerBuilder.Current
.GetControllerFactory()
.CreateController(ControllerContext.RequestContext, controller);
c.Execute(ControllerContext.RequestContext);

HttpContext.Response.Flush();
memoryStreamFilter.Position = 0;
string result;
using (var r = new StreamReader(memoryStreamFilter))
result = r.ReadToEnd();

// restore
HttpContext.Response.Filter = orgResponseFilter;
routeData.Values["action"] = orgAction;
routeData.Values["controller"] = orgController;

return result;
}
Include this in a (base) controller or in a class that has access to the controller to be able to use it.

The code in this post is licensed under the Apache 2.0 license, which in practice means you have permission to use it.

14 August 2009

Peeking into the ASP.NET MVC source with the debugger

Peeking into sourcecode of open source projects can be very useful: you can learn from it, understand the framework you're using better, and find hidden features and maybe you can contribute to the project.

It can be very insightful to be able to step into the code with a debugger. For future reference, this is how to do it for ASP.NET MVC.

Download the source with svn from https://aspnet.svn.codeplex.com/svn/MVC.


Open the solution MvcDev.sln and check that it builds (just to know for sure).

Add a new ASP.NET MVC website to the solution and set it as startup project (it will be bold)


From the new MvcApplication, remove the reference to System.Web.Mvc


Now add a project reference to the System.Web.Mvc project.


Because the System.Web.Mvc assembly doesn't have a strong key, you have to change the references to the System.Web.Mvc assembly to exclude version info and public key token. In the TWO web.config files (one in the root of the web app, one in the Views folder) remove the Version, Culture and PublicKeyToken information from all references to the System.Web.Mvc entries. For example
<add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />

will become
<add assembly="System.Web.Mvc" namespace="System.Web.Mvc" tagPrefix="mvc" />



Now you can set breakpoints, hit F5 and start peeking around.

10 August 2009

IE, ASP.NET MVC, AJAX and browser caching

IE caches AJAX requests and won't reload the resource by default. Other browsers do it differently. I am not sure who's "right" here (this document may have the answer). But this can be very annoying behaviour in AJAX applications.

The solution is to explicitely tell IE not to cache.

On this website kazimanzurrashid posted an ActionFilterAttribute to control browser caching behaviour. I changed it a bit so it is possible to prevent any browser caching.

I now have an attribute on my base controller class:
[BrowserCache(PreventBrowserCaching=true)]

This prevents any caching by default. This can be overriden if required (which I never do).

The attribute looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace YourNameSpaceHere
public class BrowserCacheAttribute : ActionFilterAttribute
{
///
/// Gets or sets the cache duration in seconds.
/// The default is 10 seconds.
///

/// The cache duration in seconds.
public int Duration
{
get;
set;
}

public bool PreventBrowserCaching
{
get;
set;
}

public BrowserCacheAttribute()
{
Duration = 10;
}

public override void OnActionExecuted(
ActionExecutedContext filterContext)
{
if (Duration < 0) return;

HttpCachePolicyBase cache = filterContext.HttpContext
.Response.Cache;

if (PreventBrowserCaching)
{
cache.SetCacheability(HttpCacheability.NoCache);
Duration = 0;
}
else
{
cache.SetCacheability(HttpCacheability.Public);
}

TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);
cache.SetExpires(DateTime.Now.Add(cacheDuration));
cache.SetMaxAge(cacheDuration);
cache.AppendCacheExtension("must-revalidate,"
+ "proxy-revalidate");
}
}
}

25 July 2009

Please respect the IDisposable interface

A very frequently asked question about programming on the .NET compact framework is something similar to this:
My compact framework app hangs randomly when it does an HTTP request.

The Compact Framework only allows three simultaneous requests. The fourth request will have to wait until one of the other request objects is disposed. If you have time-outs or a request that blocks the application endlessly, you probably forgot to dispose the previous requests.

The solution is therefore quite simple. The GetRequestStream() and GetResponseStream() methods both return Stream objects. The Stream class implements the IDisposable interface. And, if you notice an IDisposable implementation, you should use it.
You may be lucky with a fast garbage collection, but in most cases, you won't. So, IDisposable? Please Dispose().

If you can correct the error in your own code, you are lucky. But too often I had to dig into sources of other libraries, which did not respect IDisposable implementations, let alone use it. In the case of a request or response stream, this is quite a flaw and renders the library useless for the Compact Framework.

I think libraries / frameworks should respect IDisposable interfaces when they meet one. And use them instead of blindly ignoring it. This will save a lot of people a lot of headaches.

24 July 2009

Compile a thrift api in C#

Evernote has an API in thrift. To use this api in C#, you need a thrift compiler for windows to compile the thrift files into C# generated code.

The thrift compiler has to be compiled itself, there is no binary download. Worse, you need Cygwin to compile the compiler.

- Download the Cygwin installer
- Click through to the list of components. Sort the list alphabetically and select all libraries that resemble the libraries needed summed up on the ThriftInstallationWin32 page of the thrift wiki.
- download the thrift source from the "Download the snapshot" link on the Apache Thrift download site.
- copy the thrift directory to a new dir c:\cygwin\data
- start cygwin, cd to /data/thrift

Do what's mentioned on the wiki page:
- enter the command "./bootstrap.sh"
- enter the command "./configure"
- cd to compiler/cpp
- enter the command "make"
- after the command finishes, there should be a thrift.exe in this directory.

For your and my future convenience, download the thrift.exe file here.

- download the thrift files to compile. In my case, the evernote zip file containing the thrift definition files at http://www.evernote.com/about/developer/api/
- find out you had better done that as your first step, because the zip file already contains the generated code files. Well, it was a nice exercise anyway.
- just to make myself believe that it was not entirely useless, compile the thrift files:
./thrift.exe --gen csharp evernote/NoteStore.thrift
(etc)

the output can be found in the subdirectory gen-csharp.

13 July 2009

NHibernate and the annoying log4net dependency

A patch



NHibernate has always used log4net as logging library. If you wanted to use a different logging mechanism you couldn't. Fortunately a thin abstraction layer exists, .NET Common.Logging, which much resembles the log4net interface. Common.Logging can be configured to use NLog, log4net, EntLib or a custom built-in lightweight logging.

I created a patch for the 3.0 trunk. The patch contains all changes needed to remove the dependency on log4net and replace it with a dependency on Common.Logging.

The patch files can be downloaded from this location.

The binary files are included in the zip file:
  • lib\net\3.5
    • Common.Logging.dll (updated to 2.0)
    • Common.Logging.*.dll (several logging implementations)
    • Common.Logging.Extension.dll (for unit testing, an in-memory logging implementation)

I upgraded the unit-tests as well. There had to be a few changes:
  • Some of the tests test logging. Because of this, logging had to be moved to an in-memory logger (Common.Logging does not have appender functionality). Because of this, logging that is done by the unit tests itself about the results of unit tests, won't be logged to a logfile. If this is still needed, another mechanism for this has to be found.
  • Some unit tests are not applicable in my situation (SQL Server 2005). I did not test them.
  • Two unit tests now fail on purpose. This might be a bug: the mapping document is invalid, but there is no error thrown when LogLevel != Debug. The tests used to succeed because the loglevelwas other than Debug, but I changed that. Somebody should look into those. See NHibernate.Test.MappingTest.NonReflectiveBinderFixture and NHibernate.Test.NHSpecificTest.NH712.Fixture
At this moment the new logging mechanism makes a breaking change. The config should be updated so it will configure Common.Logging. I included a test project with settings for NLog, Log4Net and the built-in console logger.

You can follow this issue at the NHibernate Jira, issue 1554

10 July 2009

Gebaren

Op de website van het gebarencentrum staat een uitgebreide woordenlijst met filmpjes van gebaren uit de nederlandse gebarentaal. Omdat wij zelf proberen onze "baby's" (0 en 2) wat babygebaren bij te brengen, maken we veel gebruik van de zoekfunctie. Die werkt helaas niet zo handig. Het gebarencentrum werkt gelukkig aan verbetering. In de tussentijd voorziet het programma "Gebaren" in een alternatieve zoekfunctie voor de website.


De inhoud van het programma Gebaren is volledig afkomstig van Het Gebarencentrum. Alle filmpjes enuitleg kunnen ook op deze website bekeken worden. Voor volledige functionaliteit, zoals grammatica, subsets van het woordenboek, enalgemene achtergronden, zie de website www.gebarencentrum.nl



Gebaren



Het programma "Gebaren" kun je op een WindowsXP / Vista computer installeren. Je computer moet wel minimaal het .NET framework versie 3.5 geinstalleerd hebben en een recente versie van Windows Media Player. Je merkt het vanzelf als je die nog moet installeren: als .NET 3.5 ontbreekt geeft de installatie een foutmelding, en als Windows Media Player geupdate moet worden, zie je dat aan het ontbreken van de filmpjes nadat je een woord hebt gezocht.



Als je het programma hebt geĂŻnstalleerd, kun je over het gebruik van het programma lezen in de handleiding. Raadpleeg de handleiding via het "Help" menu.



Twee dingen die niet aanstonds duidelijk zijn:


  1. Zoek met een Hoofdletter om niet een deel van het woord te zoeken, maar alleen woorden die beginnen met de ingetypte term.

  2. De eerste keer dat je het programma opstart, duurt het even voordat je kunt zoeken, omdat hij de lijst met woorden van de website moet downloaden.

06 July 2009

InternalsVisibleTo attribute how-to

I tried avoiding the InternalsVisibleTo attribute for our testsprojects, simply because I didn't know how it works or how I could get it to work.

But that is not a very convincing reason not to use it. So for future reference:

1. Sign the test project with your keyfile

2. navigate to the test assembly with a visual studio command prompt and get the output of this command:
sn.exe -Tp <assembly>


3. Attach the parts of the public key together to form one long string of characters, and create an attribute in the target assembly:
InternalsVisibleTo("Assembly.Name.Here, PublicKey=00240000048.....")

28 June 2009

Installer error: Please wait while the installer finishes determining your disk space requirements

Suddenly my newly created installer gave this error on the Virtual PC:
Please wait while the installer finishes determining your disk space requirements

I solved this by moving the file I added (and after which this error occurred) to another media file.
Add the second file after the first file:
<Media Id="2" Cabinet="SecondFile.cab" EmbedCab="yes"/>

And refer to this media file in the "File" element:
<File DiskId="2" ...

Using WIX to create an installer: quickstart tutorial

WIX is an open source, Microsoft-sponsored wrapper to create an MSI setup.

Because I quickly need to create a setup for a small project, and could not find a quick tutorial how to do this, I record the steps in this post for future reference. The success of a framework depends on its ability to get its users up-and-running with only one page of "getting started" reading.

1. Download and install Wix 3.0

2. Add a new Wix setup project to your existing solution for which you want to create a setup.

3. Add a project reference to the existing project from the Wix installer project.

4. Begin with the boilerplate xml
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="(create a new guid here)" Name="(application name here)" Language="1033" Version="1.0.0.0" Manufacturer="(manifacturer name here)"
UpgradeCode="(create a new guid here)">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="Media1.cab" EmbedCab="yes" />


5. Define the directories
    <Directory Id="TARGETDIR" Name="SourceDir">
<-- Program Files/app name -->
<Directory Id="ProgramFilesFolder">
<Directory Id="ApplicationRootDirectory" Name="(application name here)"/>
</Directory>
<-- Start menu/programs/app name -->
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="(application name here)"/>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop"/>
</Directory>


6. Define contents of the application dir
    <DirectoryRef Id="ApplicationRootDirectory">
<Component Id="ApplicationFile" Guid="(create guid here)">
<File Id="ApplicationFile" Name="$(var.(project-to-install name).TargetFileName)"
Source="$(var.(project-to-install name).TargetPath)" DiskId="1" KeyPath="yes"/>
</Component>
<Component Id="ConfigurationFile" Guid="(create guid here)">
<File Id="ConfigurationFile" Name="$(var.(project-to-install name).TargetFileName).config" Source="$(var.(project-to-install name).TargetPath).config"
DiskId="1" KeyPath="yes"/>
</Component>
</DirectoryRef>


7. Define the contents of the start menu folder:
    <DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="(create guid here)">
<Shortcut Id="ApplicationStartMenuShortcut"
Name="(application name here)"
Description="(nice description here)"
Target="[ApplicationRootDirectory](assemblyname here).exe"
WorkingDirectory="ApplicationRootDirectory"/>
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\(application name here)" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>


8. Define the desktop shortcut
    <DirectoryRef Id="DesktopFolder">
<Component Id="DesktopShortcut" Guid="(create guid here)">
<CreateFolder/>
<RegistryKey Root="HKCU" Key="(app name here)\Install" Action="createAndRemoveOnUninstall">
<RegistryValue Name="Desktopshortcut" Value="1" Type="integer" KeyPath="yes"/>
</RegistryKey>
<Shortcut Id="ApplicationDesktopShortcut"
Name="(app name here)"
Description="(nice description here)"
Target="[ApplicationRootDirectory](assembly name here).exe"
WorkingDirectory="ApplicationRootDirectory"
/>
</Component>
</DirectoryRef>


9. Tell installer to install the defined components
   <Feature Id="ProductFeature" Title="Main components" Level="1">
<ComponentRef Id="ApplicationFile" />
<ComponentRef Id="ConfigurationFile"/>
<ComponentRef Id="ApplicationShortcut"/>
<ComponentRef Id="DesktopShortcut"/>
</Feature>


10. And close the XML nicely
  </Product>
</Wix>


11. Build the installer and test it.

The created installer is one without any userinterface. It just installs what is has been told to install and doesn't ask the user for anything.

23 June 2009

BackLinq quickstart tutorial

Since our clients still only have the .NET framework installed, there is no possibility to use LINQ in our projects.

Enter BackLinq.

BackLinq is a library that introduces the possibility to use Linq in NET 2.0 if you use VS2008 to compile the project.

1. Download the binary from the BackLinq website.
2. Change the target framework of the VS project to .NET 2.0 instead of .NET 3.5
3. Add a reference to BackLinq.dll to the project.

If the project is a C# project, things will now work as always, because BackLinq.dll adds its functionality into the System.Linq namespace.

If the project is a VB.NET project, you have to import the namespace System.Linq in the right places (=see the error pane), or add System.Linq to the Imported namespaces in the project properties.

4. Test the project and observe that azizatif did a good job.

22 June 2009

MSMQ versions

It seems that the MSMQ versioning will make it very hard to deploy an application in a large environment.

MSMQ 2.0 was available with Windows 2000 & runs only on Windows 2000 platform.
MSMQ 3.0 comes with Windows 2003 and Windows XP.


So... which MSMQ version should we use then? It seems that we have to build different versions of our application that use different versions of the MSMQ library to be compatible in both XP and Win2K environments. And how about mixed environments? If Win2K is on the server, and the client has XP?

Sigh.

EDIT: this reply from John Breakwell (MSFT)


Hi, the problem is not as bad as it seems. I regularly use test utilities on Windows 2008 that were written years ago. MSMQ should be backward-compatible - an application developed on MSMQ 2.0 should work fine on MSMQ 3.0. Doesn't mean you won't find any discrepancies, though, just like moving any Windows application to a newer platform. The usual practice of testing and recoding if necessary applies.

Note that here I am talking about compatibility with the application code. Compatibility between machines running different versions of MSMQ is much better. The format of the messages "on the wire" is the same across all versions (but see below) so you don't have to worry as long as you are sending the same type of messages.

Obviously you can't send a message over HTTP from a Windows XP client to a Windows 2000 server as the latter doesn't have that functionality. Standard MSMQ messages, though, should work between all versions.

There is one blemish on this with very large (~4MB) messages and that is discussed here.

17 June 2009

Using MSMQ to communicate between .NET and VB6 applications

The try-out continues. In part 1 of my try-out, i succesfully installed MSMQ and setup a local queue. In part2 I was with some success able to setup communication between two different machines. In this part I will try to setup communication between a .NET application on computer 1 and a VB6 application on computer 2.

I did not use MSMQ in a VB6 application before, and there is surprisingly few documentation about it on the Bathroom Wall Of Code. But it is quite simple actually.

1. Create a new EXE project
2. Add a reference to "Microsoft Message Queue 3.0 Object Library"
3. Create a form with a button. In the button_click, add this (left out errorhandling and creation of the queue):
 Dim q As MSMQQueue
Dim msg As MSMQMessage
With New MSMQQueueInfo
.FormatName = "DIRECT:OS=COMPUTERNAME\Private$\QueueName"
Set q = .Open(MQ_SEND_ACCESS, MQ_DENY_NONE)
End With

Set msg = New MSMQMessage
msg.Label = "TestMessage"
msg.Body = "I am here"
msg.Send q

q.Close

4. Test the exe: works on my machine. I can see a message appearing in the queue, using compmgmt.msc

Now I need a .NET exe that can receive the message and do something with it.

1. Create a new C# WPF exe project.

2. Add System.Messaging reference

3. Create a form with a ListView on it, which binds to an instance variable "ReceivedData":
<Window x:Class="Project.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="332" Width="417"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<ListView HorizontalAlignment="Left" Margin="12,12,0,0" Name="listView1" VerticalAlignment="Top" ItemsSource="{Binding ReceivedData}" Height="270" Width="371">
<ListView.View>
<GridView>
<GridViewColumn Header="Data" DisplayMemberBinding="{Binding Text}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>

4. Create the ReceivedData instance variable, which is of type System.Collections.ObjectModel.ObservableCollection<QueueData>:
        private ObservableCollection<QueueData> receivedData = new ObservableCollection<QueueData>();
public ObservableCollection<QueueData> ReceivedData
{
get
{
return receivedData;
}
}

And the QueueData class:
    public class QueueData
{
public string Text { get; set; }
}


5. In the constructor, start listening to the queue. The Formatter should be an ActiveXMessageFormatter, because we are sending plain strings.
        private MessageQueue q;
public Window1()
{
InitializeComponent();

q = new MessageQueue(@"FormatName:Direct=OS:COMPUTERNAME\private$\QueueName");
q.Formatter = new ActiveXMessageFormatter();
q.ReceiveCompleted += messageReceiver;
q.BeginReceive();
}

6. In the messageReceiver handler, add the received data to the listbox by updating the bound collection:
        private void messageReceiver(object sender, ReceiveCompletedEventArgs e)
{
try
{
var msg = q.EndReceive(e.AsyncResult);
var contents = (string)msg.Body;
Dispatcher.Invoke(new Action(addInfo), contents);
}
catch (Exception ex)
{

MessageBox.Show(ex.Message);
}
q.BeginReceive();
}

private void addInfo(string info)
{
ReceivedData.Add(new QueueData() { Text = info });
}

7. And clean up when the window is closed:
        protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
if (q != null) {
q.ReceiveCompleted -= messageReceiver;
q.Close();
}
}

8. Try it out. And again, works on my machine:


Now that I have the two applications that I need, I will deploy one of them on another machine and see if the two applications will still be able to communicate.

1. Copy the VB6 exe to a virtual machine and try to send a message.

2. "The queue path name specified is invalid". That was caused by myself using the PathName property of the QueueInfo object. The PathName property only works on a local machine, but not on remote machines. I should have used FormatName (fixed in the example). I do not really see the logic behind these propertynames and it cost me quite some time to figure out what was wrong. If PathName is not able to specify remote paths, then why is it possible to include the server name in it? Well, maybe there is some use for it, for example in an AD setup.

3. try again with the fix. Don't forget to allow anonymous user on the queueu. After that, I see the message appear in the remote queue.

In the meantime I have set up another VirtualPC to find out what was wrong in step 2. The message queue that I use now, is on VPC1. VPC1 and VPC2 both have the VB6 client and are both able to write to the queue.

4. Install the WPF viewer application on VPC1 and start it: it reads and displays the messages from Vb6 client on both VPC1 and VPC2 correctly. Install same viewer on VPC2: now we created a race condition (2 WPF viewers processing messages from the same queue), but whatever: it works as well.

The last thing I want to be able to do, is send a message from the WPF application back to the VB6 exe.

1. In the VB6 form, create a Timer Timer1 which ticks every 1000 milliseconds.
2. Create an instance variable which holds another queue, initialize in Form_Load. The queue should have MQ_RECEIVE_ACCESS instead of MQ_SEND_ACCESS.
3. In the Timer1_Timer, wait for the message for 100 milliseconds and process the message if one arrived:
Private Sub Timer1_Timer()

Dim msg As MSMQMessage
Set msg = Me.receiveQueue.Receive(WantDestinationQueue:=True, WantBody:=True, ReceiveTimeout:=100)

If Not msg Is Nothing Then
MsgBox CStr(msg.Body)
End If

End Sub

4. Create the queue on the computer where it should be and assign the anonymous user the proper rights.

In the WPF application should be updated to enable it to send a message in this new queue.
1. Add the same queue just added in the Vb6 app
2. Add a button. In the click handler:
        private void button1_Click(object sender, RoutedEventArgs e)
{
outQueue.Send("WPF application says hi!");
}


Copy new exe's to VPC1 and VPC2. Start the vb6 exe, start the wpf exe and try: works on my machine.

Conclusion for now: MSMQ can be a very handy mechanism if you need to communicate between .NET and legacy VB6 applications. If there are problems, it is often not trivial to debug the problem. But on the other hand, it is a proven and mature technology, which implies a lot of knowledge and experience in the field.

16 June 2009

Registration-free COM components try-out (continued)

As described in the previous post, I am trying out Side By Side (reg free) COM, trying to solve versioning and deployment issues we have with our software. In the previous post, I looked at VB6 and COM, this post is about my adventures with .NET and COM. The conclusion is: don't use the walkthrough as is, you won't be able to get a successful regfree installation.

.NET and COM



Step 1 Read the walkthrough.

Step 2 Create the COM enabled .NET dll and the VB6 client app
Use Guid.NewGuid().ToString() to create GUIDs for the .NET assembly, class and interface if guidgen is not working for some reason. I created a new windows forms exe which copies a new Guid to the clipboard and exits. Start the vb6 exe to see if it works.

Step 3 unregister the .NET dll
with c:\windows\Microsoft.NET\Framework\v2.0.50727\regasm /u SideBySide.dll. Start the vb6 exe and see that it doesn't work any more.

Step 4 Create the manifest files for the dll and the client exe.
The example manifest in the walkthrough contains errors. FAIL. For example: //assemblyIdentity/@name=" SideBySide" should be "SideBySide", without the space. And //clrClass/@progid="SideBySide.SideBySide" should be "SideBySide.SideBySideClass".

Step 5 Do voodoo magic to embed the manifest into the dll
- Create a resource definition file which references the SideBySide.manifest file
- Create a build.cmd file which creates the resource file and compiles it into SideBySide.dll
Run build.cmd in a VS command prompt (%comspec% /k ""C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86)

Step 6 Start client.exe
Now it should work... gaaah! Automation error!

Step 7 Take hours to troubleshoot
- The error is 80070002, which is supposed to mean "file not found". There are however no entries in the windows event log, and no entries in fuslogvw by which i could get a diagnosis of the problem.
- Googling on the error is not helpful.
- The assembly should have an embedded manifest. Open the file in VS, check: obviously has the right manifest file.
- Manifest files seem to be correct. But because the example in the walkthrough had errors, i feel uncertain about it.
- Because the dll has no version information if you view the properties in Windows Explore, i though that might have to do with the problem. I tried to embed the manifest using Visual Studio. After that, it works, but that is because "register for COM interop" was still checked. Regasm-ing /u and it won't work any more. The file still has no file version properties - but i'm not sure if that is a problem.
- Tried adding the interface to the manifest file also, still fails.
- Tried to build everything from scratch: same automation error occurs.
- I was thinking: we had issues with our own software that appeared after building VB6 exe's against .NET COM dll's and then rebuilding the COM dll's. That could be a problem, so i will test it: build the .NET dll with embedded manifest file and after that rebuild the vb6 exe. Still fails.
- Ok starting from scratch again.
- Tried all variations of the manifest files i could think of: Still fails with the automation error

Step 8 Give up for now.
I have no ideas left. Do some hopeless i-give-up-but-i-dont-want-to-admit-it-browsing and hey, a tool to generate the manifest files instead of having to make them yourself. The tool is called genman32, and is made by Junfeng Zhang, who has some articles about SxS / RegFree com.

Step 9 Having new hope, try again with the genman32 tool
The tool generates a manifest using reflection and is able to embed it in the dll. The generated manifest is unfortunately not correct.. But i could correct the errors and then use the tool to embed the corrected manifest.
- Create manifest with "genman32 <dll>"
- Correct the manifest (<dll>.manifest): Remove /assembly/assemblyIdentity/@processorArchitecture and add /assembly/assemblyIdentity/@type='win32'.
- Embed the manifest in the dll with "genman32 <dllname> /add /manifest:<manifestname>

Step 10 Start the Vb6 exe
Ha! Now it works!! Double check by regasm-ing /u the assembly... still works!! The only difference with my "manual" tries is that the dll now has version information embedded as well. It seems that having this version information is not optional. The manual process described in the walkthrough removes this information, while the genman32 tool preserves it (which is compiled into the dll by Visual Studio automatically).

Conclusion


The document "Registration-Free Activation of .NET-Based Components: A Walkthrough" is not correct and it cost me time and frustration. And i am probably not the only person with this experience. I will provide this story as feedback on the article and i hope the article will be corrected.

But apart from that, the good news is: I do have a way of using .NET COM components in VB6 regfree. I should try this with .NET OCX files too...

Registration-Free COM components try-out

We have both .NET components and VB6 legacy apps. We created a communication layer between the two, both ways, using COM interop.
Unfortunately, this breaks the xcopy install for our .NET software. And introduces unexpected and nasty versioning issues.

Enter reg-free com. This might solve some of these issues. Updating is reduced to copying a new version of the dll, and it even makes possible that different versions of one COM server exist side-by-side (which happened to be the reason behind this technology in the first place).

I record my adventures using registration free COM on this blog for future reference.

VB6 and COM


Step 1 Read the walkthrough.

Step 2 Create the COM and client applications

Step 3 regsvr32 /u sidebyside.dll
And notice that the client exe will now fail.

Step 3 Create manifest files
which hold the information that makes XP find the COM server without the registry.

To know by which GUIDs the component is known, the OLE/COM object viewer is a very nice tool. It can be downloaded from the Microsoft site. The download does not include an essential dll, iviewers.dll, (obviously this has not been tested thoroughly), which can be downloaded from this location. After install, your system has not been polluted with shorcuts to any exe whatsoever, and the program can be found at this intuitive location: "%ProgramFiles%\Resource Kit"

I created a sendto command to drop the dll's onto the exe, which will then show you the information you need.

The "walkthrough" does not walk me through which GUID maps to what attribute in the xml file, but my guessing was right:
/assembly/file/comClass/@clsid maps on the uuid on "coclass SideBySideClass"
/assembly/file/typeLib/@tlbid maps on the uuid on "library SideBySide" (topmost uuid)
/assembly/comInterfaceExternalProxyStub/@iid maps on uuid on "interface _SideBySideClass : IDispatch"
/assembly/comInterfaceExternalProxyStub/@tlbid is the same as /assembly/file/typeLib/@tlbid

Step 4 Start the client exe and celebrate that it works for VB6 exe to COM dll.

Tomorrow: .NET and COM.

MSMQ continued

Created a simple server app, which creates the queue if instructed, and sends a message down the line. Also created a client app, which listenes to a queue and displays the string message. This works if used on the same machine. But how will it work if i deploy it to another machine?

Step 1: try to make the client app work with the queue name FormatName:Direct=TCP:<ip>\private$\<queuename>

Client app fails on the local machine when I use the ip address that is assigned this computer, but the client app succeeds if I use the loopback address 127.0.0.1

Step 2: copy the client app to a virtual machine that has access to the host machine.

Step 3: start the client, pointing it to the queue on the host machine.
Ouch!!
InvalidOperationException occurred: Message Queuing has not been installed on this computer.

I was silently hoping that Message Queuing would not have to be installed on client machines. In our situation we may have hundreds of client computers that will need this installation. Would there be another way of deploying MSMQ?

Step 4: read about deployment in the FAQ.
Some quotes:
"I want to configure a central queue on a Message Queuing server and have multiple remote clients read from it. Is this a good design? [..leave out some shades of gray...] No."

"The supporting server should be running the same (or later) Message Queuing version as the dependent client"

"Message Queuing does not scale well with multi-CPU computers"

And lots of cryptic error message with their explanations. If a solution requires a 133 page Word document for FAQ alone... what will it be like to work with MSMQ in the field? Looks like a horror scenario to me. Imagine getting this message from a client: "Unsupported option at CQ2QMsgF::QMsg, at (or near) line 2323". Or: "Message Queuing may function in an unpredictable fashion". How about this prose: "This error [MQ_ERROR_INSUFFICIENT_RESOURCES] can be returned by several APIs. It has several (unrelated) reasons"

The document does not answer my question so far. But this discussion seems to do. It involves a nicely formatted batch file which also acts as a configuration file for the installation that it invokes. The file should be named MSMQsetup.bat.
;@ECHO OFF 
;sysocmgr.exe /i:sysoc.inf /u:MSMQsetup.bat
;GOTO Finished
[Components]
msmq_Core = ON
msmq_LocalStorage = ON
msmq_ADIntegrated = ON
msmq_TriggersService = ON
msmq_HTTPSupport = OFF
msmq_RoutingSupport = OFF
msmq_MQDSService = OFF
;:Finished


Step 5: try out the magic batch file on my VM
Ha! it works: installation completed successfully.

Step 6: start my client app again
MessageQueueException occurred: The queue does not exist or you do not have sufficient permissions to perform the operation.
Bad UX from developer point of view: this error message does not give you very much information about how to solve this. But OK, that's what we get paid for: to solve problems that we or other developers create. So:

Step 7: Try out if settings the appropriate permissions on the queue solves the issue.
There are 2 ways to do this: 1) programmatically, 2) by starting compmgmt.msc > services > messsage queuing > private queues > right click on appropriate queue > properties and set permissions.
Setting the permissions programmatically would involve something like this:
  createdQueueu.SetPermissions(
new MessageQueueAccessControlEntry(
new Trustee("Iedereen"),
MessageQueueAccessRights.FullControl));

The "Iedereen" string is Dutch for "Everyone", which obviously is translated to the language of the OS. Very handy. I could not find a (programmatic) way to find out how the "Everyone" group is called on the local machine. But anyway, you would want to configure that and don't want to put that hard-coded in you app.

Step 8: Start the client app again on the VM
Still not working. Set the ANONYMOUS_LOGON permissions to Full Control. Still not working. Could be something with the VM / Host communication. So created the queue on the VM, tried to connect from host. Not helping.

OK I don't have a clue anymore about what could be the problem.

Try something else.
Not
FormatName:Direct=TCP:<ip>\private$\<queuename>
But
FormatName:Direct=OS:<hostname>\private$\<queuename>

Step 9: Start "server" app on host machine, "client" app on VM...
Eureka, it's working now.
Whatever.
Remove permissions for ANONYMOUS_LOGON:
Aha! A different error message:
MessageQueueException occurred: Access to Message Queuing system is denied.

So the problem with the TCP is yet unresolved, but I do have a working remote queue installation now.


By the way. The server app:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: ServerApp <queue> [create]");
Console.WriteLine(" Will send a message \"Hallo!\" down the line.");
Console.WriteLine(" Specifying the \"create\" command will create the queue.");
return;
}

var queueName = args[0];

try
{
using (var q = (args.Length == 2 ? MessageQueue.Create(queueName) : new MessageQueue(queueName)))
{
q.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
q.Send("Hallo!");
Console.WriteLine("Message sent");
}
}
catch (Exception e)
{
Console.WriteLine(e.GetType().Name + " occurred. " + e.Message);
}
}
}
}]]>



The client app:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("usage: ClientApp <queuename>");
Console.WriteLine(" reads 1 message from the given queue");
return;
}

var queueName = args[0];

try
{
using (MessageQueue q = new MessageQueue(queueName))
{
q.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
Console.WriteLine("Waiting for message...");
Console.WriteLine("Received message: " + (string)q.Receive().Body);
}
}
catch (Exception e)
{
Console.WriteLine(e.GetType().Name + " occurred: " + e.Message);
}
}
}
}

15 June 2009

MSMQ try-out

MSMQ (Microsoft Message Queuing) seems like a powerful thing:
  • Transactional
  • Robust
  • Works with both COM (vb6!) and .NET
So I decided I should at least know how it works and how I can use it in a project. There are nice .NET wrappers around it, abstracting it away, like NServiceBus, but I should know how it works anyway before using any framework.

Step 1: try out an example from The Bathroom Wall Of Code
Failed. "MSMQ is not installed on this machine". It needs an install of an extra windows component! FAIL! How can I ever use this on my server that is managed by Mordac? Note to self: try out Ayende's Rhino Queues, xcopy install, with no dependency on MSMQ.

Step 2: install MSMQ
Software > Add Windows Component > MSMQ > Installation failed for unclear reasons. Some searching revealed that I had to reset the Distributed Transaction Log by some obscure command. Should of course have thought of that before trying the install. Retry install: fail again. This component has been registered for removal. Ok. Restart machine. Retry again. Now it installs.
Update: John Breakwell blogged about the details and solution of this problem here.

Step 3: Make the queue

MessageQueue q = MessageQueue.Create(@".\Private$\TestQueue");

Step 4: create and configure the queue in 2 applications
MessageQueue q = new MessageQueue(@".\Private$\TestQueue");
q.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });

Step 5: send message from application 1
q.Send("hi!", "message");

Step 6: receive the message in application 2
Console.WriteLine((string)q.Receive().Body);

Step 7: Watch it work.

31 March 2009

Quickstart tutorial for NHibernate.Search

To use NHibernate.Search one has to extract the instructions from a lot of different places, which sometimes have outdated information. 
This blog post is a summary of how I was able to successfully add an NHibernate.Search-powered search function to an existing NHibernate project.

This guide assumes you have an NHibernate project and know how it works.

1. Assemblies
Add references to NHibernate.Search.dll and Lucene.Net.dll to your project. There is no official download for NHibernate.Search, you have to compile it yourself using the nhcontrib project. But you could also download the dll's I compiled on this site.

2. Configuration
Some properties have to be added to the Configuration object:
  
  'configure directory where indices are stored
  cnf.SetProperty("hibernate.search.default.directory_provider", _
    GetType(FSDirectoryProvider).AssemblyQualifiedName)
  cnf.SetProperty("hibernate.search.default.indexBase", "~/Index")
  cnf.SetProperty("hibernate.search.default.indexBase.create", "true")

  'event listeners to automagically update indices
  cnf.SetListener(NHibernate.Event.ListenerType.PostUpdate, _
    New FullTextIndexEventListener())
  cnf.SetListener(NHibernate.Event.ListenerType.PostInsert, _
    New FullTextIndexEventListener())
  cnf.SetListener(NHibernate.Event.ListenerType.PostDelete, _
    New FullTextIndexEventListener())

The direcotry where the indices are stored can be a relative path by using the ~ as the application root. This will be translated by NHibernate.Search to a real path.

3. Add search attributes to model 
  <Indexed(Index:="MyDomainClass")> _
as attribute on the class definition 

  <Field(Index.Tokenized, Store:=Store.No)> _
For searchable textfields 

  <DocumentId()> _
For the Id field.

4. Decorate the session 
Decorate the session with a full text searchable session:

Imports NHibernate.Search
[...]
session = Search.CreateFullTextSession(sessionFactory.OpenSession())

5. Convert existing data 
Often you will want existing data to be searchable. This can be done by indexing the old data once. New entries and changes will automatically be merged with the existing indices.
Here is a generic method to index existing data.

   '''
    ''' create full text index for type T
    '''
    Public Sub CreateIndex(Of T)()
      'decorate the session
      Dim fullTextSession = _
        NHibernate.Search.Search.CreateFullTextSession(Session)
      Using trans = fullTextSession.BeginTransaction()
        Dim query = fullTextSession.CreateQuery( _
          String.Concat("from ", GetType(T).Name) _
        )
        For Each thing In query.List()
          fullTextSession.Index(thing)
        Next
        trans.Commit()
      End Using
    End Sub

6. Add search to your repository (or [some layer] )
Now you can search with nhibernate! Lucene has some powerful features, but the nhibernate search in its simplest form looks like this:

  Dim query = fullTextSession.CreateFullTextQuery(Of MyDomainClass)(  _
    "MyProperty:searchterm1 OR AnotherProperty:searchword2" _
  )
 Dim results = query.List(Of MyDomainClass)

I hope this helps.

14 January 2009

How to remove objects from the unity container

Removing objects from a Unity container can be done by using the LifetimeManager. You can even use the built-in LifetimeManager without building your own:

Dim container As New UnityContainer()
Dim lifetimeManager As New ContainerControlledLifetimeManager()
Dim someThing as New SomeThing()

container.RegisterInstance(Of SomeThing)(someThing, lifetimeManager)

Assert.AreEqual(someThing, container.Resolve(Of SomeThing)())

lifetimeManager.RemoveValue()

'we get a new instance here
Assert.AreNotEqual(someThing, container.Resolve(Of Something)())