Wednesday, September 10, 2008

Identifying servers in a web farm with IIS headers

Once your application has been deployed to a web server farm, it can become tricky to track down problems.  Particularly when a problem occurs intermittently.  Sometimes these intermittent problems are such because they are occurring on only one machine of a web farm.  

Identifying the problem server can be rather challenging.  Often the first attempt is to modify your local DNS (in Windows it's the HOSTS file) to point the site URL to a single machine.  Depending on how your web farm is set up you may not be able to do this because the individual machines may not be visible to you.  Only the farm's pool address is visible.  Furthermore, sometimes the problems we encounter do not manifest themselves when running on a single environment (otherwise we'd have caught them in development right??).  To complicate the matters moreso, often the only chance you have to identify on which machine the problem occurred is right when it occurred, as in, when you are staring at the application crash page.  Simply attempting to replicate the problem after you set up your tracking may not be enough.

A simple solution I have implemented on our staging and production web farms involves nothing more than the built in HTTP headers supplied by IIS.  First, just add an HTTP header to each machine in the farm that contains the name of the machine, or any other unique value that you can map to the machine:

Then, when you browse to the site or are looking at an error message, you can open a tool like Fiddler or FireBug to view the page's HTTP header information for the response.

Particularly with a tool such as FireBug or another DOM inspector, you can get immediate information without having to start any kind of tracking tool or needing to relaunch the site.

Thursday, September 04, 2008

Correction: Chrome does cheque speling

I recently posted about chrome and complained that it doesn't have spell check.  Apparently it does.  But it doesn't seem to work in Blogger.  Odd considering Google owns Blogger.

Spellcheck seems to work in regular textboxes, but Blogger's "compose" view doesn't use that it seems.  I'm not sure what it uses though.  I tried the Chrome page inspector but I can't see what it's doing.

Oh well, I suppose that's part of being beta.

Wednesday, September 03, 2008

Enriching .NET Windows Apps with the WebBrowser control

I am currently working on a desktop product upgrade project.  The old versions were developed on the .NET 1.1 platform.  They utilized a web browser control to display information for printing.  Unfortunately the support for hosting a web browser control in a windows form was poor so the original development team had to create their own control with hooks into the Internet Explorer objects and such to do it.  Among other changes, we are doing a complete re-write of this application in .NET 2.0.  (We still need to support some older platforms, so 3.0 wasn't an option.)

One of the requirements of the new version dictated that we need to do some more intricate display of the information.  The prime display control candidate for this information is a "tree-grid" hybrid.  The standard .NET 2.0 toolbox simply doesn't have a control that can handle what we need (a shame really).  There are many third party controls that could do this, but that introduced a learning curve that our project timeline simply wouldn't support.  Obviously, there is additional cost involved with such a control as well.  As I evaluated what we needed to achieve, and being a web developer, I naturally looked towards HTML as a solution.  The desired output could be executed very simply with standard HTML constructs.

While analyzing the current application architecture and scoping out how we were going to integrate the changes, we decided to change the data storage strategy as well.  The application uses a local MS-Access database with a small set of tables to store standard relational data.  Given that we really don't need relational access to the ancillary tables of the data model, we determined that we could simplify the whole thing greatly by reducing the data architecture to a single table with a blob of XML to represent the bulk of the record's detail.

Now that we have serialization going on for database storage, the natural step was to use that XML for display.  One of the great additions made in fx 2.0 is the System.Windows.Forms.WebBrowser control class.  This provides simple, native hosting of a web browser inside a windows form.  To solve the complex display problem, we placed a web browser control on the main user control, serialize the data model object instance to XML, apply an XSL transformation to it then feed the result directly to the web browser control in the form.  The browser control has the property "DocumentText" which you can write HTML directly to.  Elegant, simple and surprisingly fast.  A natural side effect of this strategy is that it becomes trivial to change the view of the data: simply develop a different style sheet and provide a switching mechanism.

While generating XML, transforming it to HTML and displaying it on the form was now very easy with the browser control, the big question was, how do we interact with it.  

In order for the browser to interact with the user control, it must be exposed to COM by being decorated with the COMVisibleAttribute class.

public partial class OurUserControl : UserControl

This exposes the object to COM and thus allows the COM based browser to see and interact with it.  Now we need to tell the browser what to interact with.  The browser control has the property "ObjectForScripting".  You give this property any object in your windows application context.  In our case, when the user control is created, we hand the browser the actual control instance.

public OurUserControl()
webBrowser1.ObjectForScripting = this;

This exposes the object to the web browser's window as "window.external".

In order for the browser context (i.e. the HTML DOM) to call the methods on the win form context scripting object (the windows user control), we need to make some methods visible.  This is simply a matter of making a public method on the object you have exposed to the browser:

//this is managed code in the win forms application
public void DoSomething(args...)
//do stuff in the windows app here

The browser can now call that method by calling the document window's "external" object.

/* This is "client-side" javascript living
 in the HTML sent to the web browser */
function doSomething(){

Now you can call this javascript method as you would in normal HTML.

When it comes to argument types, there seems to be a certain amount of implicit conversion going on.  In my experiments, I found that a javascript based variable that was typed to a numeric value came into the managed method call as such.  So if you used "parseInt(...)" in javascript, you should expect that the managed call will receive a proper System.Int32 as the argument value.  In most cases what I'm dealing with are strings so the argument values slip right through without any fuss.  If the value type doesn't match up, you'll get an exception about it for sure.

The web browser control also allows you to access the browser's DOM.  The Document property returns an instance of HtmlDocument.  From here you can get at an instance of an HTML control and manipulate the DOM as you see fit from the managed code.  The browser control itself has many methods and properties to direct it as needed.

All in all, I'm finding the web browser to be a compelling tool for developing richer windows forms applications using my existing web knowledge and without the need for purchasing additional control libraries.  In a very short time, my team has been able to do some very good proof of concept work that is leading into rapid development of something that only a short time ago had me very concerned for the project timeline.  We did some initial tests with a basic prototype on various platforms to ensure we weren't getting into a snag.  The application ran happily on Windows XP, Windows 2000 and Windows Vista.  Those are our target platforms, so I'm pleased with the outcome.

The recent (yesterday) release of Google Chrome suggests that we might one day be able to integrate the open source WebKit rendering engine as an alternative to the embedded Internet Explorer browser control.  Aside from the obvious decoupling of our application from I.E., this could also mean that our application could potentially run on a non-windows .NET platform such as Mono.  However, we'll stick with I.E. and windows for now.  The enhancements we are making with the web browser rendering and .NET 2.0 upgrade are enough for this go around.

Google Chrome: Shiny, new and very cool

I just finished reading the 38 page comic style technical overview book on Chrome.  They implemented some pretty interesting things.  Of definite interest is the process isolation used to separate the tab and plugin processes.  As a GMail user, I notice the performance affects on the other tabs when I'm running GMail.  Also, with the bloated Flash and PDF plugins, it seems that so many page loads just bog everything down.  It will be interesting to see what the performance is like with Chrome.  

Other particularly interesting features are the "incognito" mode tab that does not log any history and the new-from-scratch javascript engine/virtual machine they are calling V8.

A couple things I've already noticed that I'm a little dissappointed with: There doesn't seem to be an automatic spell check like Mozilla has, and the zoom feature is only a text size changer, not a natural zoom like Opera or the latest Mozilla.  Perhaps they are still working on that.

Despite being currently beta, as are so many of Goggle's applications, it's pretty fair to say that it's still better than many other applications.  Being open source, it will be fun to see all the projects that spin off from the various pieces that make up this new browser.

I'm definately going to give Chrome a whirl and see how my web experience changes.  And of course, now I need to test all my web applications to see if they behave!