Comments

I recently needed to investigate and fix this rather unpleasant sounding issue. It was occurring, seemingly at random, on a live web service but could not be replicated in tests. Occasionally the web service was throwing the exception when we made a call to delete a list of records from the database.

The web service uses the NHibernate object relational mapper (ORM) tool to map our c# classes (domain objects ) to database tables. NHibernate was throwing this exception when we tried to delete the records:

NHibernate.StaleStateException: Unexpected row count: 0; expected: 1

What is a stale state?

This issue was not one we had seen before and had us scratching our heads for a while. The first step was to understand what the exception itself meant.

After some reading up in the NHibernate documentation it was more clear what the issue was. NHibernate was complaining that the in-memory model of the database data had become stale, or in other words out of date. So when NHibernate tried to persist the requested deletion to the database it was finding that it could not complete the operation.

Why was our state stale?

So, all well and good, we knew what the stale state was. However, it was rather more difficult to pin down why it was happening, especially because we were unable to reproduce the error during testing.

It was only examining the event logs for the web service which enabled us to understand why this was happening. The event logs showed that 2 separate instances of the web service were being called almost simultaneously on separate threads. Both of those instances were basically calling the same delete operation on the same list of records.

So the first instance would succeed in deleting the records, but the second instance would then also try to delete the records. Of course the second instance would fail, as there were not longer any records to delete.

Preventing the stale state (odour eaters?)

Once we understood why the exception was occurring it was a straight forward re-factoring exercise to prevent it in future. In our case the code could be updated so that the delete operation never needed to be called in the first place, so this was an effective fix.

The detailed event logging on the web service proved invaluable in solving this issue, without this it probably would of taken much longer to figure out what was happening!

Comments

I recently encountered this exception consuming a web service from an application:

System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://service.foo.com/baa.asmx

The code ran fine locally and only caused an exception running on the web server. Initially I thought it could be to do with the web server running a newer version of the .NET framework. But this proved not to be the case.

Eventually I got the issue tracked down and it was a simple typo in the settings on the live environment. The system has the web service addresses stored in a database and the application assigns these dynamically at runtime (via the Url property). We have it set-up this way to enable the test application to send to a different end point from the live application. However this does rely on the same service being available on the end point and in this case it wasn’t.

So we were changing the URL to be:

http://service.foo.com/baa.asmx

But it needed to point to here instead:

http://service.foo.com/baas.asmx

Note the s on the end of the service method name, one little character causing one pesky SOAP exception!

Comments

We have log4net setup to record events from a web application in a database. However it had been running for a couple of weeks and the database table was getting rather large (144,000 records at last count). This was causing performance issues when accessing the database table and also taking up quite a bit of disk space. Obviously the database needed some kind of maintenance script to keep the size under control.

I investigated the log4net support for maintaining the size of the database table and there is none built in as such. However the configuration is fairly verbose and it allows you to define the SQL script itself which is run to log the events. So with a fairly straightforward amendment to this script I was able to keep the database size in check:


<appender name="EventLogAdoNetAppender" type="log4net.Appender.AdoNetAppender">          
  <bufferSize value="0" />          
  <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <connectionString value="{your conn string}" />
  <commandText>
    <![CDATA[INSERT INTO EventLog ([Date],[Thread],[Level],[Logger],[Message],[Exception])
             VALUES (@log_date, @thread, @log_level, @logger, @message, @exception);
             DELETE FROM EventLog WHERE Date < DATEADD(Day, -7, GETDATE())]]>
  </commandText>
  <parameter>
    <parameterName value=”@log_date” />
    <dbType value=”DateTime” />             
    <layout type=”log4net.Layout.RawTimeStampLayout” />          
  </parameter>
  …
</appender>

The key changes are to the commandText element. The default command just runs an insert query, this has been updated above to also run a delete query. This will remove any records in the EventLog table which are over 7 days old. It can easily be changed to a different record age by amending the second parameter of the DATEADD method. It was also necessary to wrap the command in a CDATA element because the delete query contains an reserved XML character (<).

I’m aware that this is not the most efficient way to implement this, an alternative would be to add a scheduled task to the SQL Server Agent, however we do not have access to this on the database server. Also I prefer how the maintenance is built into the log4net configuration here so it will now work immediately on any database server without the need for separate configuration steps.

Comments

After a good few months in hibernation the guilt of leaving my poor pet project half-finished has finally got to me!

I was also spurred on by several new (and not so new) software releases that I would like to try out:

The first step I needed to take was to upgrade the project to use the new release of Sharp Architecture and MVC 2. The Sharp Architecture wiki has a decent upgrade guide and I was able to get most of the way there by following this. However there were a couple extra step I needed to take in my project:

Upgrade to Fluent NHibernate

I think my project may have been on an earlier version than that in the guide because I needed to upgrade the Data project to use Fluent NHibernate. The issues here were pretty obvious as there were several compilation errors. I found the easiest solution was to generate a new empty Sharp Architecture project from the 1.6 template, then copy across the amended files in the NHibernateMaps folder.

This got the application to compile OK, however there were a couple of differences in the configuration from my project.

Primary Key Convention

One of the data unit tests was failing when trying to access an entity using the .Get(id) method. This was strange as the entity was being loaded OK in the setup method. I was also getting an exception from the website when trying to add an entity to the database:

Invalid object name ‘hibernate_unique_key’.

The problem was due to a change in the PrimaryKeyConvention class. The convention for generating primary keys has been changed from Native() to HiLo(“1000”). So instead of the first record having a key of 0 it would now try to use 1000. Changing this setting back to Native() fixed the problem straight away.

Cascade Conventions

The other issue I encountered occurred when trying to add a new ingredient to a recipe:

Cannot insert the value NULL into column ‘IngredientFk’, table ‘recipebook.dbo.RecipeIngredientDrafts’; column does not allow nulls. INSERT fails. The statement has been terminated.

This error pointed to a problem with NHibernate not saving changes to associated entities; it was trying to save a new RecipeIngredientDraft record without first saving the new Ingredient record. This issue could be resolved by adding a call to instance.Cascade.SaveUpdate() in the ReferenceConvention and HasManyConvention classes.

After fixing these issues the application worked just fine :)

Comments

Its pretty straight forward to generate a simple web page, there are several software tools available that will generate the mark up code for you. However, even using these tools, it is easy to misuse tags and not conform to the XHTML standards. If you were unfortunate enough to follow the previous link, you may well be thinking,

What does it all mean, my web page looks fine so does compliance really matter?

This is a valid point, however compliance is widely regarded to be important for a number of reasons. These are pretty well documented around the web so I ll just highlight a couple of the reasons that I think are most important.

Firstly a compliant web page should be assured of displaying fairly consistently across all major browsers, both now and in the future. Unfortunately some browsers are more compliant than others, internet explorer still demands some extra attention but it is much improved since the days of IE6. The newer browsers which have come onto the market, such as Firefox and Chrome, generally display compliant pages very well. Secondly I think that compliance is important as it makes the content more accessible to machine readers. For example the readers used by search engines will be able to read and index the page content easier, which will help increase traffic to the site. This theory has actually been tested and there is some evidence to back up the claims that Google prefers valid HTML and CSS.

Keep it clean

The first step to compliance is to separate the HTML mark-up from the presentation using a CSS (Cascading Style Sheet) document. This helps ensure that the web page is short and the content is easy to find. Apparently search engines are busy guys and they just don t have the time to be reading all that content on your site. So they only read up to a certain number of characters, if your important content is pushed too far down the document then there is a rick that it will never get indexed.

I ve gone for a fairly straight forward layout on the recipe stash site, with a fixed width page of 960 pixels to target resolution widths of 1024 and above. The header, footer and main content are all in a single column. This layout can be created in CSS without too much trouble. I ve tried to use the HTML tags as they were intended originally, for example the menus are tagged as an unordered list of elements, then styled to display horizontally.

There is an unfortunate limitation with HTML, it does not support curved corners. So I ve used to Nifty Corners to create the curved effect on the top navigation menu and latest recipes section:

recipestash-nav

Nifty Corners is a JavaScript based tool which adds HTML and CSS to the page when it is loaded to create the effect of curved corners. The other option I considered to create the curved corners was to cut out images of the corners themselves and position them in the corners of the HTML elements. However I decided to use Nifty corners for a number of reasons:

  • No images are required
  • The generated HTML mark-up is compliant
  • The implementation is fast just one line of JavaScript to call!
  • It degrades gracefully (If JavaScript is not available then it does nothing)

Exceptions to the rule

I mentioned earlier that internet explorer interprets style sheets differently to other browsers. This is so pronounced for version six that a completely different style sheet would be needed to create the same visual layout. I ve decided that this would take up too much of my time and have instead used the universal ie6 style sheet, along with an upgrade message for anyone that is using IE6.

I m currently running on Windows Vista and it is pretty tricky to test for all versions of internet explorer. There are two main methods that can be used to test, either install a virtual machine running Windows XP with IE6 installed natively or use the IETester program. I ve gone for the IETester program, mainly because it is quicker to install and doesn t take up a huge chunk of my hard drive. I ve tried it out and it displays the basically styled page I would expect to see in IE6 mode:

IETester2

The deficiencies of Internet Explorer versions seven and eight are less pronounced and I only needed to modify a couple of elements to give the same appearance to the web page:

  • Added fixed widths to the main div elements so margins are applied
  • Extra div element wrapper on the so the margin is applied
  • Add fixed widths to the navigation menu elements to fix nifty corners in ie7

Validating the page

It would be difficult to judge when the mark up and styling of a web page is actually valid, fortunately there are many tools freely available on the web to help. During development I generally use the HTML validator Firefox extension. This provides a little icon in the bottom right corner of the web browser that indicates whether the current page is valid or not. Clicking the icon brings up a list of validation errors for the page. I like this tool as it is quick to browse through a site and check the validation on each page.

I ve also included links to the World Wide Web Consortiums XHTML and CSS validation services in the page footer. This will submit the current page to their online validation tools and display a report with suggestions for any problems that are found.

Well that s just about all I ve got on compliance, however if you re after a more hard line message then you can check this out!

Copyright © 2016 - Hook Technologies Ltd - Powered by Octopress