Wednesday 29 May 2013

Problem running a Windows service with Topshelf and Spring.Net

Problem

I had written an application using Spring.Net for dependency injection - and some of the other features it provides - and Topshelf. The application could then be written as a console application and then installed and run as a Windows service using Topshelf’s handy ‘install’ command line parameter.
I was using XML files to configure Spring.Net. This turned out to be significant.

The application worked sweet as a nut as a console application and installed successfully as a Windows service. However, when I tried to run the Windows service using net start all I got was “The service is not responding to the control function”.




Solution

In the app.config file I had a spring configuration section that referenced external files for the spring.context:

<spring>
    <context>
      <resource uri="file://Config/SpringContext.xml" />
      <resource uri="file://Config/SpringDataAccess.xml" />
      <resource uri="file://Config/SpringVelocity.xml" />
    </context>
    <parsers>
      <parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
      <parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" />
      <parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" />
    </parsers>
</spring>

The XML configuration files were set to “Copy always” and had been copied into the application directory correctly.

Poking around in the Event Viewer I spotted an interesting error log message. Essentially it said “Exception: Error creating context 'spring.root': Could not find file 'C:\Windows\system32\Config\SpringContext.xml'.”

That was weird because the path (C:\Windows\system32) is not where I had put the application but clearly it was where the Windows service was being run from.

A quick solution was to reconfigure the application to use embedded resources for the configuration files:

<spring>
    <context>
      <resource uri="assembly://Assembly.Name.Here/Namespace.Here/Config.SpringContext.xml" />
      <resource uri="assembly://Assembly.Name.Here/Namespace.Here/Config.SpringDataAccess.xml" />
      <resource uri="assembly://Assembly.Name.Here/Namespace.Here/Config.SpringVelocity.xml" />
    </context>
    <parsers>
      <parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
      <parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" />
      <parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" />
    </parsers>
</spring>

The service now started correctly.

Sunday 5 May 2013

JavaScript functions

JavaScript functions can be declared in a number of ways.

Basic declaration

function write(message) {
    var div = document.getElementById('message');
    var para = document.createElement("p");
    var node = document.createTextNode(message);
    para.appendChild(node);
    div.appendChild(para);
}

In the example above the function called write is declared and can be called later in JavaScript (e.g. write("My message here")).

Assigned function

Functions can be assigned to variables. There are basically 2 ways to do this: 1) name the function and assign it to a variable, 2) don’t name the function and assign it to a variable.

var writeFunc = function write(message) {
    var div = document.getElementById('message');
    var para = document.createElement("p");
    var node = document.createTextNode(message);
    para.appendChild(node);

    div.appendChild(para);
};

In the example above the function is named (write) and assigned to a variable (writeFunc). The function must now be called via the variable name (e.g. writeFunc("My message here")). Note the semi-colon at after the last curly brace.

var writeFunc = function (message) {
    var div = document.getElementById('message');
    var para = document.createElement("p");
    var node = document.createTextNode(message);
    para.appendChild(node);

    div.appendChild(para);
};

In the example above the function is not named (it’s an anonymous function) but is still assigned to a variable as before.

Anonymous function immediately invoked

(function (message) {
    var div = document.getElementById('message');
    var para = document.createElement("p");
    var node = document.createTextNode(message);
    para.appendChild(node);

    div.appendChild(para);
})("This is a message.");

In the example above the function is anonymous. However, because it is wrapped in brackets and has an argument passed in (see the last line) it will be immediately invoked.

Function overloading

Function overloading doesn’t work the same way in JavaScript as it does in C#. Declaring functions with the same names but different arguments doesn’t result in overloaded functions, rather the last function to be declared overwrites the others. Note that if you call a function and pass in too many arguments any unnecessary arguments are simply ignored.

Don’t forget that object parameters are passed by reference and primitive types by value.

Use an object to hold arbitrary values

One option is to add an object parameter as the last argument to a function. This object can be used as a bag into which you can put whatever parameters you want.

function functionTest(param1, param2, options) {
    write("param1: " + param1);
    write("param2: " + param2);
    write("options.opt1: " + options.opt1);
    write("options.opt2: " + options.opt2);
}

window.onload = function () {
    functionTest("This is param1", "This is param2", {opt1:"This is option1", opt2:"This is option2"});
}

Use the ‘arguments’ object

Another option is to use the arguments object. This is described as:

“An Array-like object corresponding to the arguments passed to a function.” [1]

function functionTest() {
    write("arguments[0]: " + arguments[0]);
    write("arguments[1]: " + arguments[1]);
    write("arguments[2]: " + arguments[2]);
}

window.onload = function () {
    functionTest("This is arguments[0]", "This is arguments[1]", "This is arguments[2]");
}

 

References

[1] https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments