User Interface

Things have been a little vague lately. At the end of last week and Monday, I finally got clean Ajax communication twixt hither and yon. JSON.NET, it turns out, does a fine job of sending the object. I haven't taken the time to understand the algorithm exactly but it contains data deeply enough to support my current requirement. As I get past the demo phase, I'm sure I will revisit the topic. I actually made the old demo, category list that clicks to reveal a list of details, work. It made for a good boundary.

So, I turn my mind to user interface. I have an incumbent application with a particularly old-school user interface. It works surprisingly well but it's looks stodgy. I figure I need to find an approach that does two main things: organize a lot of complexity into some sort of workspaces or toolsets or something, and have some snap so that this thing sells once it's complete.

I actually spent a couple of days reading about user interface. I am amazed at how little real discussion there is. There's Jacob Nielsen, of course. He's really the main game if you are interested in learning things about user interface. In two days, the only practical advice was his. His 2008 best apps on the web list included the observation that toolbars has won. He had been reluctant before, but a number of the best apps had made good use of them.

I looked around for some info on that idea and found that the world is surprisingly short of straightforward user interface frameworks. Seems like imagination in the jquery world ended at with tabs and widgets. Eventually though, I found two toolbar packages. Both were pretty nice. One, however, was abandoned. The other had a nice thing it calls a backstage. A menu in the upper left that opens an overlay page structured into a two level heirarchical menu and an information pane (though I haven't been able to get the info pane to work yet). You can check it out HERE.

Actually, that's V2.0. The guy has something else he wants to do with it but hasn't gotten around to it. He says, no repository, just grab the code.

That's cool with me and I did. 

Custom Error Page IIS7

Just spent a happy hour or so debugging misleading error messages to find out that Microsoft requires an obscure second action to activate custom error pages in addition to setting a custom error page.

To serve a custom page on an error (in my case, 404), you go to the IIS control panel, select the site and double click on the icon marked Error Pages.

This will give you a nice list of the usual error messages. You can double click on one of them and, using the handy browse button, select your new error page.

Then you can go to a web browser and induce an error (in my case, typing the domain with a gibberish page name). You may be rewarded with a 500 error message that says that you cannot have an absolute file path in website.config, or some such (sorry I didn't get it exactly). You will look at the path name, read other path names, and eventually change the "C:" to "%SystemDrive%". This may reward you with more complicated error messages.

Eventually, it will give you a 404. Hooray, that's what I was looking for. Except that it's the standard page. You may spend more time trying to figure out how you misrepresented the file name. You may notice the Feature Settings button and try it. Putting the file path into its Custom Page field won't work either.

It turns out that you need to click the radio in the Feature Settings that says, "Custom Page." Then it will pay attention to the fact that you entered a custom page already.

Do I sound bitter?

nHibernate and JSON.NET

This is a problem with LINQ to SQL as well, or maybe it's just a problem with the .NET JSON converter. Whichever, the problem is that the retrieval from database to an object graph produces data that, when given to Json(), produces an error claiming that it has discovered recursion. Of course, it's right. A Relationship object links to a Patron object that contains a list of relationships (one to many) each of which links back to the Patron which has a list of Relationships.

My initial plan was to write something that prunes the object before sending it to Json(). This is a tricky bit of work and the general case still eludes me. But, along the way, a coworker told me about JSON.NET, a converter that is claimed to be vastly superior. So far, it is. At first, it produces the same error. However, it has a setting, "ReferenceLoopHandling.ignore," that makes it go away.

I'm not sure if the resulting data structure is complete (there is evidence that it prunes a little too much) or if it has more settings to make it work better. Still, it's a start.

Sometimes Things Work

I'm working toward a routine that prunes nHibernate object graphs (that's what the cool kids call them) so that they can be serialized for JSON transmission without getting an error because it's recursive. In the process, I've been experimenting with ways of handling objects retrieved by NH. Bottom line, it is easy and works the way one would hope. In particular, I have retrieved a triple object, people, bars and relationship from the people side, then changed the data on some of the relationship records. A simple flush() and the correct records get back to the database with changes in place. The amount of not having to write a bunch of save routines I am enjoying is marvelous. Similarly, I made a routine to populate the database and it works nicely, too. FYI

IIS7 Static Variables Refer to the Entire Server Context

I just had a conversation that saved my bacon BIGTIME!!

Static variables are shared across the entire server. If you declare a static variable in your web application and have ten thousand people using it, when one of them does something that sets the variable, it changes it for everyone. There does not appear to be a way to create any sort of global variable that is not also universal.

The workaround is to use the http session object instead (though this is a crime, in my opinion).

DataType ShouldBeStatic = (DataType) System.Web.HttpContext.Current.Session["ShouldBeStatic"];

What I can't believe is that this isn't emblazoned all of the universe when you google ".NET tutorial". There is nothing like it in the LAMP world. I can't imagine what sort of problems I would have suffered if I had not learned this and then the problems of going through an entire application to fix it. Bullet Dodged!

Reorganize a Visual Studio Project

I have been working on this project for a month. When I started, I didn't know anything about it and was inexperienced in .NET development. As a result, I created a project file structure that I do not like and will not work as the effort, and team, grows. This week is the week to get a code repository up and to create a testing/demo web server. That means it is also time to organize the files correctly.

What I want to do is simple. I want to rename my projects from their idiosyncratic starter names to, and I quote, UserInterface, DatabaseModel, TestProject. I want to move them out of their default directory and into one that is named after the project and is structured so that I can manage other things. The initial structure is to be, SourceCode (home to the three named above), SharedSoftware (home to nHibernate, mbUnit, etc), and ManagementFiles (home to stuff that arguably should not be in source control, especially Virtual Studio control files).

This would be, in my old world, about two hours work, and that would include reconfiguring Apache to point at the new directories. In my new world, I have just completed the chore and it has taken a full day, a good eight hours. 

Among the reasons for this is the fact that, in true Microsoft fashion, they make no provisions for user flexibility. Specifically, they knit VS projects together with a "solution" file (.sln) that is hard-coded into the file system. It cannot be moved, nor can the code it manages. Worse, it insists on storing it in the middle of the source code. Anyone else that downloads the project is stuck with your preferences. It appears to combine the very worst combination of traits. Make catastrophic by the fact that Microsoft has provided no tool to edit this thing or to relocate the project. I have tried one million things. It is the dumbest thing I have ever heard.

But, I did devise a way to do it (including the relocation of the .slnfiles) and here is the story...

Reprise, the goals:

1) rename projects
2) create new directory structure (with .sln outside SourceCode)
3) put existing code into it
4) make it work correctly with Visual Studio

And an idiosyncracy: I prefer to divide the projects into separate solutions. The more usual way is to have one "solution" containing several projects. I prefer this because it allows me to have a separate, complete window for each solution. This is not possible for projects within a solution. Consequenlty, the three projects listed above, will each become a separate solution, each in its own directory. (Where needed, they refer to each other by reference.) This means that there is a .sln for each of them. My solution is the ManagementFiles directory inside of which I have directory, SolutionFiles, and inside that, one called, tqwhite. This is so that other people can store their own solution files without stomping on mine.

How to do it:

1) back up!!

2) create your new directory structure (inside ManagementFiles, create the SolutionFiles directory but not ones for each sub-project, VS will do that later)

3) distribute your source code into it; remove the .sln and .suo, keep the .csproj

4) open visual studio; if you moved, not copied, your source, when you select each solution, it will tell you it's lost and ask to remove it; say yes

For each sub-project:

5) sub-project, create a new project (for me, it's an ASP.NET MVC Empty Project). It will ask where to put it. The correct answer is NOT "SourceCode", it goes in ManagementFiles, in the place where you want the .sln for this sub-project to reside.

6) choose the new project info, right-click and Remove it.

7) go to File->Add->Existing Project; choose the .csproj file for your source code (in the new sub-project directory); it will ask for a name, use the new one that you like

8) build the project

When you quit the project and return, you should see your new projects and they should work. If you're as lucky as me, one of the three will. I ended redoing it several times to get them all going.

You might be able to use, File->New->Project from Existing Code to add your sub-projects to the newly created (renamed and relocated) .sln files. I did it for the javascript project because I lost its .csproj.

Finally, when you move your stuff to SharedSoftware, you are going to have to reassign your projects' references.

Good GUID

I have implemented the good kind of guid, uudi.comb. It required that I change my industry supplied data type from "string" to "System.guid". This does not appear to have any adverse consequences.

Yay!

I Take It Back

Upon further experimentation... 1) if I tell the <many-to-one> to be not-null="false", it creates a correct schema that works. This new schema demonstrates that I was also wrong about the foreign key constraint. 2) With the new schema, the foreign key constraint doesn't need to be removed

Many to Many with Data in the Join Table

When I wrote the last post, I had gotten nHibernate to create objects. They were specified to be in a many-to-many relationship and, though I can't remember the exact details of that moment, the objects were being created but the relationship was not. Since then, I have been really struggling to create that relationship.
The biggest thing that I have learned is that many-to-many is no longer fashionable and, I think, appropriately so. It is replaced by symmetrical one-to-many associations with a single relationship table. That is, a person visits many bars, and a bar has many visitors, but they really have a codependent relationship with each other. Which is to say, a person has many codependent relationships that help him be drunk and the bar has many codependent relationships that help it contribute to the delinquency of the culture.
For me, the nicest thing about this is that it removes the behind the scenes magic. It also makes use of that joining table. After all, it's not like there is some special kind of table for this. It's a table with data and making it a relationship rather than something invisible makes it more useful by giving us some semantics that allow us to store data about the relationship. The drunken person might want to note the number of blackout experiences enjoyed in each codependent relationship. The bar might want to record how many times police were involved for any particular codependency.
When I worked out how to use nHibernate <bag> elements and the <many-to-one> element and which entity they refer to (simple but slippery), I got an error message, "Cannot insert the value NULL into column." The column referred to is the foreign key in the join table. It's as if nH tries to create the join table first, before it knows the private keys of the other two records. Since I am using MSSQL, it allows you to specify whether a field is nullable and, nHibernate is really keen on using that when it generates a schema.

I communicated with the nice people on the google group (If you want to see the details, look at the technical conversation here) and tried many things. Inverse="true" did no good. Using <ibag> neither worked nor made sense. I tried using <set> just in case (couldn't figure out the type of the object property for that and it makes no sense because there can be duplicates and no sequence is implied). I tried using interlocking many-to-many. I tried changing the order of creation and saving in the app. Nothing mattered.

The only way I made any progress was to tell the database that the field is nullable but then, it complained that I was violating a "foreign key constraint". Sure enough, reading the generated schema, nHibernate adds this to the database, too. A foreign key constraint basically tells the database what two table/column pairs relate to each other and will not allow that to be screwed up. Good idea, unless you are using an ORM that creates the objects first and subsequently updates the foreign keys. I suspect that the update is when the violation occurs. I was far enough into it then that I knew there was no way I was going to convince nH to do it differently. I edited the schema again and Voila! Two concrete objects and a join table with correct foreign keys.

Tough luck on the database constraints.

Finally, as I write this, I am thinking about that guid. It's a long string and it's used as a key. I had chosen an nHibernate generator type that turned the guid into a string (uuid.hex) and can see that there is nothing that can be alphabetized about them. This is worrisome. I looked at the other guid generator schemes in nH (here) and found one that had a link to the rationale behind it. First, the article confirmed my suspicions. In simple tests, a guid is takes thirty times longer than an integer key. Big problem. This guys new guid generator makes for good, local commonality in the beginning characters. This reduces the penalty from thirty to .1, a 300x reduction. Unfortunately, using this method (guid.comb) gives me a type conversion violation in C#. I guess I have more work to do.

nHibernate is getting there

Phew! This is a hard thing to do.

I have done two major things lately. First, I made it so that I can generate database schema based on nHibernate mappings as well as generate update scripts that will revise the database to match changes in the nH mappings. This latter is one of the things I am most excited about. I can't tell you how annoying I have found it over the years to try to keep code and database schemas in sync. 

The other is that I have managed to write data using nHibernate. I haven't got all functions shaken down yet, but it's getting close.

The main trick for schemas was getting mapping to work. The nH docs are not very instructive, especially to a C# newbie. I had the devil of a time figuring out (and eventually just asked and got the answer; I wish I was rich enough to just pay someone so I didn't feel obligated to make a good faith effort to find out on my own) how to deal with object properties that are objects themselves. In this case, I had a property called name, that was a BaseName type with it's own properties of First, Last, etc. Turns out that the <component> element is the one to use. Once I heard that, the example of how to use it was for a Name object. 

The other thing that was hard was to deal with many-to-many. There are obvious provisions for this in the nH docs but it isn't really explained. The main thing is that I had to add a property to my class for the elements of the related collection. That is, if Widgets and Goodies are in a many-to-many relationship (maybe I should have chosen People and Bars, many People visit each Bar has many People visiting it) then you will, at some point need to assign one to the other, eg,

firstWidget.barList.add(someBar);
firstWidget.barList.add(anotherBar);

I had to learn how to create firstWidget.barList. This is probably easy for experienced C# people. For me, I had to started learning about enumerable types. List<Widget> (and List<Goodie>) work for schema generation. when I tried to write data, I got, "Unable to cast object of type." Ouch.

Turns out that nH, behind the scenes, changes the type of that grouping property (actually, I used the <bag> element) to its own kind of enumerable type. "List" is actually a type based on the interface, "IList". I don't thoroughly understand this typing business, but nH can't change out an actual type but it can assign a type to a property specified with an interface.

Bottom line, I used IList<Widget> and IList<Goodie> and Voila! I got me some database writing.

But there's more!

These are smaller things that I knew about, but that came to bite me anyway. First, because of the whole lazy loading thing, properties need to be "virtual". This was easy to debug because the error message was very explicit. In my case, I am working with an industry xsd-based type system so I got to use me some serious regular expression mojo to make it happen.

My text editor of choice is BBedit. I needed to change all the public properties from "public PropertyName" to "public virtual PropertyName". Unfortunately, the classes are public as well (public partial class BlahBlah{}) so I had to exclude the public classes from the substitution. Eventually I found someone that had constructed a conditional regex pattern that did the job:

     (?(?=^(the_only_string_you_dont_want_to_match)$)^$|.*)

Since it was constructed to deal with an entire line, I changed it to:

     public +(?(?=(partial)) |.*)

and replaced it with

     public virtual \1

I have run into the other major issue several times and so, when I hit it again, it was easy. The xml mapping files, class.hbm.xml, property needs its output directory to be set as an Embedded Resource. If they are, things work. If not, "No persister for ...".

In a closely related point, remember to set your xml file property Build Action to "Copy Always."

Onward!!