Blog

Oracle on Windows Seminar

I recently attended an “Oracle on Windows” seminar in London, organised by Oracle and sponsored by Quantix.

There were four speakers:

  1. Mark Whitehorn – independent DB consultant
  2. Julian Boneham – Quantix
  3. Paul Brankin – Oracle
  4. Jules Lane – Oracle

The talk from Quantix was unfeasably dull; full of sales-speak (“…all vertical markets…”) and delivered by a bloke who clearly wasn’t interested.

Paul Brankin talked about data silos and how this architecture arises (it’s simple to manage initially), how it becomes limiting or fragmenting in business terms (due to inaccessible data, and under- or over-utilization of hardware resources dedicated to a single silo) and how Oracle’s Real Application Clustering (RAC) can help solve the problem. Specifically, Oracle has an Active-Active database failover solution, whereas Microsoft’s SQL Server has only Active-Passive (in the form of mirroring).

Jules Lane gave an overview of the Oracle middleware application stack. Interestingly, he said …we are not really expecting people to write Java code any more…, but instead to rely on component configuration and code-gen tools alone when building middleware applications. The Oracle BPEL Process Manager is akin to BizTalk, as a business process orchestrator, although seems more advanced. No mention of WF/WCF in Jules’s talk, though of course this technology is still fairly new. Also interesting was the Oracle Webservices Manager, which allows policy-based access control to web services, including ASP.NET web services.

In general, the talks by Oracle and Quantix were disappointing; they were generally too sales-focussed, and their “Oracle on Windows” pitch was somewhat embarassed, as if Windows was something they only supported grudgingly. Far more engaging was the first session, by the independent consultant Mark Whitehorn.

Mark – much to the later ire of the Oracle speakers – said categorically that all three major database engines (DB2, Oracle and SQL Server) are extremely competant database engines, and that debates about their relative merits are pretty arcane and irrelevent. He noted that many people choose databases on religious grounds, proffering out-of-date evidence for why one engine is superior to another (e.g. “it’s a poor man’s Sybase fork” or “it cannot even row-lock”).

He stressed the need to look at the other kinds of tools and features available for these engines as more important reasons to choose one over the other:

  • Analysis (e.g. Business Intelligence [BI] tools)
  • Middleware connectivity
  • Server/Database Management

Mark then went on to give some lucid examples of real-world BI analysis (on 150 year old plant specimen records, collected by Charles Darwin!) to demonstrate how useful this kind of analysis can be, in combination with human domain experts.

He finshed by commenting on the new Spatial data types offered by the three database engines, and how some amazing results can be had using “mashups” (think Google Maps).

Mark was an extremely entertaining speaker, who clearly is an outstanding specialist in his field, and it was a pleasure to listen to what he had to say. By contrast, the other speakers seemed rather awkward and apologetic! It was clear from this seminar that Oracle is still well-placed for extremely high-end database applications, but similar resiliency CAN be implemented using SQL Server, at a reduced cost. All three vendors, but especially Oracle and Microsoft, are increasingly competing head to head for the Enterprise AND medium-size database markets, and this trend is set to continue for the next five years at least.

Subversion made easy: VisualSVN Server

Subversion is fairly straightforward to install and maintain, but VisualSVN Server makes the process on Windows almost trivial:

  1. Download
  2. Run Installer
  3. err, that’s it

It bundles Apache and the SVN server, and comes with a nifty Admin console which makes it easy to change repo permissions. It even provides pretty repo browsing via XSLT in the web browser.

IISAdmin – multiple sites on Windows XP

The inability to run multiple concurrent websites from IIS under Windows XP is a pain. I need to run Server 2003 and IIS 6 to do that, and live with the resulting slowdown

IISAdmin Screenshot

There is a handy free utility, IISAdmin, which mitigates the worst aspect of the IIS 5 limitation: the need to reconfigure the Default Web Site each time I want to work with a different site. IISAdmin allows you to create new websites, each permanently pointing to a different set of files on disk. The limitation (probably in IIS 5 on XP) is that only a single site can be started at a time.

Work around limitations of VS 2005 Deployment Projects with Windows Services

I needed to deploy a Windows Service using an MSI. The project was built in VS 2005 using .Net 2.0; so far, so good.

The problem arose when I wanted to have the Service write to its own Event Log, rather than the default Application log. The standard Installer class from System.Configuration.Install, which otherwise does a fine job of installing the Windows Service, proved less than ideal because it automatically creates an EventLogSource with the same name as the Service executable, and sets its event log to be Application.

The solution lies in the way in which the Installer class contains a series of other installers in the Installer.Installers collection, which in turn contain other installer objects.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;

namespace MyService
{
  [RunInstaller(true)]
  public partial class ProjectInstaller : Installer
  {
    public ProjectInstaller()
    {
      InitializeComponent();

      //
      // ProjectInstaller
      //
      this.Installers.AddRange(new System.Configuration.Install.Installer[] {
            this.serviceProcessInstaller1,
            this.serviceInstaller1});
    }

    private void serviceInstaller1_BeforeInstall(object sender, InstallEventArgs e)
    {
      RemoveEventLogInstallers(this, 0);
    }

    ///
    /// Recursive method to remove EventLogInstaller Installers from the Installers collection.
    /// This is needed to avoid automatic setting up of the event logs
    private static void RemoveEventLogInstallers(Installer installer, int depth)
    {
      Console.Out.WriteLine(String.Format("Number of installers at depth {0}: {1}", installer.Installers.Count, depth));
      for (int i = installer.Installers.Count - 1; i >= 0; --i)
      {
        Installer childInstaller = installer.Installers[i];
        Console.Out.WriteLine(String.Format("Installer {0} at depth {1} is of type: {2}", i, depth, installer.GetType().Name));

        RemoveEventLogInstallers(childInstaller, depth + 1); //recurse

        if (childInstaller is EventLogInstaller)
        {
          Console.Out.WriteLine(String.Format("Removing Installer {0} at depth {1} because it is of type: {2}", i, depth, childInstaller.GetType().Name));
          installer.Installers.Remove(childInstaller);
        }

      }
    }

    private void serviceInstaller1_BeforeUninstall(object sender, InstallEventArgs e)
    {
      RemoveEventLogInstallers(this, 0);
    }
  }
}

Search recursively through the entire tree of Installer objects and remove any installer whose type is EventLogInstaller, and the problem is solved! Make sure to do this before Install and before Uninstall, otherwise the (un)installation does not complete successfully.

Calling Javascript from C#

Call JavaScript from C# code, passing parameters and returning results.

I came across a need to call JavaScript methods on HTML code inside a web page from a C# WinForms application. How could that language gap be bridged?

It turns out that Type.InvokeMember() does the trick when using a [Internet Explorer] WebBrowser control to load a web page.

using mshtml;
...
private AxSHDocVw.AxWebBrowser axWebBrowser1;
...
///
 /// Retrieves a reference to the HTML element containing a DIV. /// JavaScript methods are implemented on this element itself. /// 

/// A reference to the HTML element holding the JavaScript methods
private HTMLDivElementClass GetContainer()
{
 HTMLDivElementClass container = null;
 IHTMLDocument2 doc = axWebBrowser1.Document as IHTMLDocument2;

 if (null != doc)
 {
  foreach (IHTMLElement element in doc.all)
  {
   if (element.id == "My_Container")
   {
    container = element as HTMLDivElementClass;
    break;
   }
  }
 }

 return container;
}

///
 /// Gets the text from the container /// 

/// A string containing the text of the container
private string GetText()
{
 string result = null;
 HTMLDivElementClass div = GetContainer();
 if (null != div)
 {
  Type type = div.GetType();
  result = (string) type.InvokeMember(
    "GetText",
    BindingFlags.InvokeMethod,
    null,
    div,
    null);
 }   

 return result;
}

The HTML page loaded in the WebBrowser control has a DIV element with an id of “My_Container”, attached to which is a method called GetText(), which returns some arbitrary text.

Having acquired a reference to the DIV on which the JavaScript method is declared (using GetContainer()), the JavaScript method is called using the InvokeMember() method of the Type class instance; the return value is cast to a string.

Discussion

There is every reason why this should NOT work, but the implementers of the WebBrowser control decided that JavaScript methods living within the DOM should be accessible as first class object members at runtime (in this case, via IDispatch). Nice!

Result

C# code can call arbitrary JavaScript within an HTML page! The only limitation is that the return types of the JavaScript methods can be only simple types (even DateTime is too complex).