16 March 2008

JSON services revisited: using a Dictionary as a generic parameter

Somebody at Microsoft deserves a Nobel Prize. Well, that is maybe a bit strong, but I ran into the problem that I wanted to create JSON scriptserver that would accept a 'parameter bag' of unknown size and type. I expected problems in the serialization, since Javascript typing is at best a bit lax, but it turns out that when you define a web service with a parameter of type Dictionary<string, object> dict, the JSON serializer automatically derives the object types from the javascript data! It works like this: suppose we define the following method:
[WebMethod]
public string DictMethod(Dictionary<string, object> dict)
{
  StringBuilder b = new StringBuilder("C# reports<BR/>");
  foreach( string s in dict.Keys )
  {
    b.AppendFormat(string.Format("{0}:{1}={2}<BR/>", s, dict[s].GetType(), 
                   dict[s]));
  }
  return b.ToString();
}
We can call this method from javascript like this
<script type="text/javascript">
  function LoadDict()
  {
    dict = new Object();
    dict["test1"] = "Joost";
    dict["test2"] = 21;
    dict["test3"] = true;
    dict["test4"] = 9999999999;
    dict["test5"] = new Date(2008,09,12,13,14,00);
    DictService.DictMethod( dict, ProcessResult );
  }

  function ProcessResult( WebServiceResult )
  {
    document.write( WebServiceResult );
  }
</script>
If you attach the LoadDict javascript function to some client side event (The OnClientClick of a button for example) and launch it, you will see the following output: C# reports test1:System.String=Joost test2:System.Int32=21 test3:System.Boolean=True test4:System.Int64=9999999999 test5:System.DateTime=12-10-2008 11:14:00 So you can see, the javascript string converted into a true .NET string, the value 21 into an Int32 - but the value 9999999999 is too long for an int and is converted into a Int64, a.k.a. long - I really like that one, for it shows true craftmanship of the programmer ;-). The "true" javascript value is converted into a Boolean finally, the javascript Date is converted into a neat DateTime. And presto, all your stuff is converted into real .NET objects. Of course, you should always used typed parameters when possible, but for some generic solutions this may come in very handy. Complete code downloadable here.

08 March 2008

Running and debugging a Windows Managed Service directly from Visual Studio.NET

Developing a Windows Managed Service (i.e. a service written in .NET ;-) ) is a lot easier than it used to be, still it can be a real PITA to debug, especially in the early stages, and even more so when the service is a kind of server and something goes wrong with the communication. You are continually running in circles:
  1. Stop running service
  2. Replace binaries
  3. Start services
  4. Attach Visual Studio debugger to process
  5. Launch your client process
  6. Find bug
  7. Fix bug
  8. Repeat until no more bug.

Life could be so much easier if you could launch the service from Visual Studio and see how it behaves. And the fun thing is, you can.

1. Create a new service project in your solution
If you already have a service project you can skip this step. I'll add a service project DemoService with a Service MyService in it with not too complicated functionality:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;

namespace DemoService
{
  public partial class MyService : ServiceBase
  {
    public MyService()
    {
      InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
      Console.WriteLine("OnStart");
    }

    protected override void OnStop()
    {
      Console.WriteLine("OnEnd");
    }
  }
}

2. Change the application output type
Right-click the DemoService project, choose "Properties", click tab "Application". Default this says "Windows application" - change this to Console application

3. Add debug mode methods to your service class

#if DEBUG

  public void StartService()
  {
   OnStart(null);
   Console.WriteLine("MyService started, press >ENTER< to terminate");
   Console.ReadLine();
  }

  public void StopService()
  {
   OnStop();
  }
#endif
4. Add debug mode code to the Main method
Open the "Program.cs" file in the service project, and change it so it looks like this
using System;
using System.Collections.Generic;
using System.ServiceProcess;
using System.Text;

namespace DemoService
{
  static class Program
  {
    /// 
    /// The main entry point for the application.
    /// 
    static void Main()
    {
#if DEBUG
      MyService s = new MyService();
      s.StartService();
      s.StopService();

#else
      ServiceBase[] ServicesToRun;

      ServicesToRun = new ServiceBase[] { new MyService() };

      ServiceBase.Run(ServicesToRun);
#endif
    }
  }
}

And that's it. You can now run the 'service' as a program in debug mode - it will pop-up a console window in which the 'service' runs and says OnStart MyService started, press >ENTER< to terminate

If you hit enter, you will just be able to see "OnEnd" passing by before the window closes. Of course, normally you will launch a thread of some kind in the OnStart method, or you will start a WCF service, and then you can see the dynamic behaviour of the 'service' while it runs by adding more "Console.WriteLine" calls - or, since it is already a process inside VS.NET, see it hit breakpoints or the exception you have been hunting all week now. And by setting the solution to "Multiple Startup" you can start both 'service' and client in one go.

And if you make a release build, all this stuff will be left out and the service will be compiled as a proper service which can be installed and will run in the usual way.

CAVEAT: be aware that the 'service' is running with your login credentials when it runs in a console window, and not as 'System'. This method is therefore not applicable when debugging access releated problems.

04 March 2008

Simplyfying refactoring by making things obsolete

A very simple one I ran into today - when you are refactoring things, sometimes old methods are no longer required, but for the sake of backward compatiblity your want to retain them. To make sure your own code no longer calls the deprecated method, simply use the ObsoleteAttribute:
[ObsoleteAttribute("Warning you want the compiler to give")]
public void ObsoleteMethod()
{
  // ....
}
If you now recompile your program, every call to ObsoleteMethod displays the message "Warning you want the compiler to give" in the output window - you might want to change that message to something more useful ;-).

03 March 2008

Starting an external program in the same directory

Especially in development/demo scenario's you sometimes need to start an external program. In my case, it was a simple batch file that more or less terminated and restarted a Map Server service in a rather ungraceful way. But sometimes you want to go for simple. First, you have to find out in which directory your external program is. This is the same directory as where your program runs:
string assemblyBasePath =
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
then, you have to create the full path to your executable, for instance
string exec = Path.Combine(assemblyBasePath, "yourbatchfile.bat");
and finally, you have to launch the process:
ProcessStartInfo psi = new ProcessStartInfo(exec);
psi.WindowStyle = ProcessWindowStyle.Hidden;
Process proc = Process.Start(psi);
proc.WaitForExit();
and that's all there is to it. The call to proc.WaitForExit() makes sure that your own program waits for the batch file "yourbatchfile.bat" to complete, while ProcessWindowStyle.Hidden prevents a console window popping up. If you do want to see the console window, for debugging purposes for example, use ProcessWindowStyle.Normal instead