06 June 2009

Hosting a CGI program as a REST service on the Azure .NET Service Bus (allowing anonymous access)

The point of this posting is threefold: I want to show how you can make REST services on the .NET service bus, how you can allow anonymous access to these, and that anything that is accessible by an URL can be hosted on the .NET service bus. For my example I am going to host a WMS Service by UMN MapServer - which is in fact a CGI program - on the .NET Service bus, but you can host anything you want. I am going to assume that you have Visual Studio 2008, .NET 3.5 SP1, the Azure tools and toolkits CTP May 2009 installed, that you have access to the .NET Services portal and that you know how to create a solution for a .NET Service on that portal. Setting the stage Create a new solution with two projects: a console application and a WCF Service library. I have called my solution "CloudMapExample", the console app "CloudMapRunner" and the library "CloudMap.Contracts" Setup the console application Add references to "System.ServiceModel", "System.ServiceModel.Web" and the Service library you have just created. Add an app.config, and make sure it looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="WMSServices"
   type="System.Configuration.NameValueSectionHandler" />
  </configSections>
  <WMSServices>
    <add key="DemoSrv"
   value="http://localhost/MapServer/mapserv.exe?map=d:/MapServer/CONFIG/Demo.map"/>
  </WMSServices>
</configuration>
This of course requires you to have setup MapServer. Don't worry, you can also set a url to a HTML page or ASPX page running on your local machine mocking this behaviour. Setup the service library Right-click the CloudMap.Contracts project, select the "WCF Option" tab and unselect the checkbox before "Start WCF Service Host blah blah blah" to prevent the WCF host popping up every time you test your project. Then, delete App.config, IService1.cs and Service1.cs Finally, add references to "System.ServiceModel.Web" and "System.Configuration" Add the service contract Add to the service library an interface IWMSProxyService that looks like this:
using System.ServiceModel;
using System.ServiceModel.Web;
using System.IO;

namespace CloudMap.Contracts
{
  [ServiceContract]
  public interface IWMSProxyService
  {
    [OperationContract]
    [WebGet(UriTemplate = "WMS/{map}/*")]
    Stream WMSRequest(string map);
  }
}
Notice the WebGet attribute "UriTemplate". The asterisk is a wildcard that tells WCF that any url starting with this template is mapped to the WMSRequest method. A nifty trick, since the idea is that I can call the method like "http://host/baseurl/WMS/MyMap/?key1=value&key2=value. "MyMap" will automatically be populated into the "map" parameter of the method "WMSRequest". How the rest of the querystring will become available is shown in the service implementation. Add the service implementation class
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.ServiceModel.Web;
using System.Configuration;
namespace CloudMap.Contracts
{
  public class WMSProxyService : IWMSProxyService
  {
    public Stream WMSRequest(string map)
    {
      Console.WriteLine("Proxy call!");
      var wms = GetWMSbyMap(map);
      return RelayUrl(string.Format("{0}{1}{2}",
                      wms,
                      (wms.Contains("?") ? "&" : "?"),
      WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters));     
    }

    private string GetWMSbyMap( string map )
    {
      var services = ConfigurationManager.GetSection("WMSServices")
               as NameValueCollection;
      return services != null ? services[map] : null;
    }

    private Stream RelayUrl(string urlToLoadFrom)
    {
      var webRequest = HttpWebRequest.Create(urlToLoadFrom) 
         as HttpWebRequest;
      // Important! Keeps the request from blocking after the first
      // time!
      webRequest.KeepAlive = false;
      webRequest.Credentials = CredentialCache.DefaultCredentials;
      using (var backendResponse = (HttpWebResponse)webRequest.GetResponse())
      {
        using (var receiveStream = backendResponse.GetResponseStream())
        {
          var ms = new MemoryStream();
          var response = WebOperationContext.Current.OutgoingResponse;
          // Copy headers      
          // Check if header contains a contenth-lenght since IE
          // goes bananas if this is missing
          bool contentLenghtFound = false;
          foreach (string header in backendResponse.Headers)
          {
            if (string.Compare(header, "CONTENT-LENGTH", true) == 0)
            {
              contentLenghtFound = true;
            }
            response.Headers.Add(header, backendResponse.Headers[header]);
          }
          // Copy contents      
          var buff = new byte[1024];
          var length = 0;
          int bytes;
          while ((bytes = receiveStream.Read(buff, 0, 1024)) > 0)
          {
            length += bytes;
            ms.Write(buff, 0, bytes);
          }
          // Add contentlength if it is missing
          if (!contentLenghtFound) response.ContentLength = length;
          // Set the stream to the start
          ms.Position = 0;
          return ms;
        }
      }
    }
  }
}
Now this may look a bit intimidating, but in fact it is just a little extension of my WCF proxy example described earlier in this blog. The 'extensions' are pretty simple: first of all the method "GetWMS" searches for a configuration section "WMSServices" in the App.config and then tries to retrieve the base url of the WMS defined by the value of "map". It then concatenates the rest of querystring, which is accessible by the not quite self-evident statement "WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters", to the url found in the config section and calls it, passing the parameters of the query string to it. Anyway, don't worry too much about it. This is the more or less generic proxy. The point is getting it to run and then hosting it on the .NET service bus. Add code code to host the service Open the "Program.cs" file in the Console application, and make it look like this:
using System;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using CloudMap.Contracts;

namespace CloudMapRunner
{
  class Program
  {
    static void Main(string[] args)
    {
      var serviceType = typeof(WMSProxyService);
      var _host = new WebServiceHost(serviceType);
      _host.Open();

      // Code to show what's running
      Console.WriteLine("Number of base addresses : {0}",
        _host.BaseAddresses.Count);
      foreach (var uri in _host.BaseAddresses)
      {
        Console.WriteLine("\t{0}", uri);
      }
      Console.WriteLine();
      Console.WriteLine("Number of dispatchers listening : {0}",
        _host.ChannelDispatchers.Count);
      foreach (ChannelDispatcher dispatcher in 
               _host.ChannelDispatchers)
      {
        Console.WriteLine("\t{0}, {1}",
          dispatcher.Listener.Uri,
          dispatcher.BindingName);
      }

      // Exit when user presser ENTER
      Console.ReadLine();
    }
  }
}
This basically just starts up the service. Everything between the comments "// Code to show what's running" and "// Exit when user presser ENTER" just displays some information about the service, using code I - er - borrowed from Dennis van der Stelt when I attend a WCF training by him at Class-A some two years ago. Notice I am using a WebServiceHost in stead of the normal ServiceHost. As long as you run your code locally, ServiceHost will do as well, but not when you want to harness your service in the cloud. But this is the only thing you need to take care of in code to make sure you can painlessly move from a locally hosted WCF service to the Azure .NET service bus - the rest is just configuration. Adding basic WCF configuration To get the service to work a REST service, you need to add the following configuration to the app.config of your console application:
<system.serviceModel>
  <services>
    <service name="CloudMap.Contracts.WMSProxyService" >
      <endpoint address="" binding="webHttpBinding"
        behaviorConfiguration="WebHttpBehavior"
        contract="CloudMap.Contracts.IWMSProxyService"
        bindingNamespace="http://dotnetbyexample.blogspot.com">
      </endpoint>
      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:8002/CloudMapper" />
        </baseAddresses>
      </host>
    </service>
  </services>
  <behaviors>
    <endpointBehaviors>
      <behavior name="WebHttpBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>
The usage of [WebGet] and the webHttp tag are covered in a previous post so I'm skipping the details on that. Run the console application, and you will see something like this in your command window: Number of base addresses : 1 http://localhost:8002/CloudMapper Number of dispatchers listening : 1 http://localhost:8002/CloudMapper, http://dotnetbyexample.blogspot.com:WebHttpBinding If you have, like me, configured the proxy to be used for a WMS service you can now enter something like "http://localhost:8002/CloudMapper/WMS/DemoSrv/?SRS=EPSG:4326&FORMAT=GIF&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=PERCEEL,GBKN_BIJGEBOUW,GBKN_VERHARDING,GBKN_HUISNR&TRANSPARENT=TRUE&BBOX=5.855712890625,51.8221981833694,5.86669921875,51.8289883636691&WIDTH=256&HEIGHT=256&REASPECT=FALSE" in your browser and then get a map image. Nice format, WMS, isn't it? :-) Next - to the clouds and beyond ;-) Make a new .NET Services solution Go to http://portal.ex.azure.microsoft.com and make a solution. I have called mine "LocalJoost" and let us suppose the password is "dotnetbyexample" Add reference to ServiceBus dll In your console application, add a reference to Microsoft.ServiceBus.dll. On my computer it resides in "D:\Program Files\Microsoft .NET Services SDK (March 2009 CTP)\Assemblies" Add .NET service bus configuration In your app.config, change "webRelayBinding" into "webHttpRelayBinding" Then, change the baseAdress from "http://localhost:8002/CloudMapper" to "http://localjoost.servicebus.windows.net/CloudMapper/". Notice: "localjoost", the first part of the URL is the solution name. Yours is likely to be different. Finally, in your app.config, add the following configuration to the behaviur "WebHttpBehavior", directly under the "<webHttp />" tag:
<transportClientEndpointBehavior credentialType="UserNamePassword">
  <clientCredentials>
     <userNamePassword userName="LocalJoost" 
                          password="dotnetbyexample" />
  </clientCredentials>
</transportClientEndpointBehavior>
If you now run your console application, you will see this: Number of base addresses : 1 http://localjoost.servicebus.windows.net/CloudMapper/ Number of dispatchers listening : 1 sb://localjoost.servicebus.windows.net/CloudMapper/, http://dotnetbyexample.blogspot.com:WebHttpRelayBinding. Now your REST service is callable via the Service bus. It is THAT easy. You only have to replace "http://localhost:8002" in your browser by "http://localjoost.servicebus.windows.net" and there you go. Well... almost. Instead of a map you get a site called "http://accesscontrol.windows.net" that asks you, once again, to enter the solution name and password. And THEN you get the map. Enable anonymous access For an encore, I am going to show you how to allow anonymous access to your proxy. Whether or not that is a wise thing to do is up to you. Remember that your service is now callable by anyone in the world, no matter how many firewalls are between you and the big bad world ;-) Add the following configuration data in the system.serviceModel section of your console application
<bindings>
  <webHttpRelayBinding>
 <binding name="allowAnonymousAccess">
   <security relayClientAuthenticationType="None"/>
 </binding>
  </webHttpRelayBinding>
</bindings>
and add bindingConfiguration="allowAnonymousAccess" to your endpoint. This is what your systems.serviceModel section of your app.config should look like when you're done:
<system.serviceModel>
  <bindings>
    <webHttpRelayBinding>
      <binding name="allowAnonymousAccess">
        <security relayClientAuthenticationType="None"/>
      </binding>
    </webHttpRelayBinding>
  </bindings>

  <services>
    <service name="CloudMap.Contracts.WMSProxyService" >
      <endpoint address="" binding="webHttpRelayBinding"
       bindingConfiguration="allowAnonymousAccess"
       behaviorConfiguration="WebHttpBehavior"
       contract="CloudMap.Contracts.IWMSProxyService"
       bindingNamespace="http://dotnetbyexample.blogspot.com">
      </endpoint>
      <host>
        <baseAddresses>
          <add baseAddress="http://localjoost.servicebus.windows.net/CloudMapper/" />
        </baseAddresses>
      </host>
    </service>
  </services>
  <behaviors>
    <endpointBehaviors>
      <behavior name="WebHttpBehavior">
        <webHttp />
        <transportClientEndpointBehavior credentialType="UserNamePassword">
          <clientCredentials>
            <userNamePassword userName="LocalJoost"
                                 password="dotnetbyexample" />
          </clientCredentials>
        </transportClientEndpointBehavior>
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>
And that's all there is to it. Moving a service to the cloud is mostly configuration, and hardly any programming. Are we spoiled by Microsoft or what? ;-) Complete sample downloadable here

07 May 2009

Cutting images with PresentationCore

In my business cutting images into smaller images is something that happens quite often these days, since tile based mapping systems like Google Maps, Virtual Earth and OpenLayers are becoming ever more popular. For the past few years I have been using GDI+ as my workhorse, but last week I've kissed it goodbye. Over are the days of messing around with Graphics and Bitmap and not forgetting to dispose them. Enter PresentationCore with the System.Windows.Media.Imaging classes! To use this API, you need to make references to both PresentationCore.dll and WindowsBase.dll. I created a small sample cutter class like this:
using System;
using System.Windows;
using System.Windows.Media.Imaging;
using System.IO;

namespace LocalJoost.ImageCutting
{
  public class ImageCutter
  {
    private string _fileName;
    public ImageCutter(string fileName)
    {
      _fileName = fileName;
    }

    public void Cut(int TileSize, int TilesX, int TilesY)
    {
      var img = new BitmapImage();
      img.BeginInit();
      img.UriSource = new Uri(_fileName);
      img.CacheOption = BitmapCacheOption.OnLoad;
      img.EndInit();

      var fInfo = new FileInfo(_fileName);

      for (int x = 0; x < TilesX; x++)
      {
        for (int y = 0; y < TilesY; y++)
        {
          var subImg = new CroppedBitmap(img,
                   new Int32Rect(x * TileSize,
                          y * TileSize,
                          TileSize, TileSize));
          SaveImage(subImg, fInfo.Extension, 
            string.Format( "{0}_{1}{2}", x, y, fInfo.Extension));

        }
      }
    }
 
    private void SaveImage(BitmapSource image, 
                           string extension, string filePath)
    {
      var encoder = ImageUtilities.GetEncoderFromExtension(extension);
      using (var fs = new FileStream(filePath, 
              FileMode.Create, FileAccess.Write))
      {
        encoder.Frames.Add(BitmapFrame.Create(image));
        encoder.Save(fs);
        fs.Flush();
        fs.Close();
      }
    }
  }
}
You construct this class with a full path to an image file as a string, and then call the "Cut" method with tilesize in pixels (tiles are considered to be square) and the number of tiles in horizontal and vertical direction. It then goes on to cut the image into tiles of TileSize x TileSize pixels. Notice a few things:
img.CacheOption = BitmapCacheOption.OnLoad;
makes sure the image is loaded in one go, and does not get locked The trick of cutting the image itself is done by
var subImg = new CroppedBitmap(img,
               new Int32Rect(x * TileSize,
               y * TileSize,
               TileSize, TileSize));
and then it is fed to a simple private method that saves it to a file. Last, I do not check if the image is large enough to cut the number of tiles you want from. This is a sample, eh? The sample uses a small utility class that gets the right imaging encoder from either the file extension or the mime type, whatever you pass on to it
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace LocalJoost.ImageCutting
{
  /// 
  /// Class with Image utilities - duh
  /// 
  public static class ImageUtilities
  {
    public static BitmapEncoder GetEncoderFromMimeType(string mimeType)
    {
      switch (mimeType.ToLower())
      {
        case "image/jpg":
        case "image/jpeg": 
          return new JpegBitmapEncoder();
        case "image/gif": 
          return new GifBitmapEncoder();
        case "image/png":
          return new PngBitmapEncoder();
        case "image/tif":
        case "image/tiff":
          return new TiffBitmapEncoder();
        case "image/bmp": 
          return new BmpBitmapEncoder();
      }
      return null;
    }

    public static BitmapEncoder GetEncoderFromExtension(string extension)
    {
      return GetEncoderFromMimeType( extension.Replace(".", "image/"));
    }
  }
}
Not only are the System.Windows.Media.Imaging classes easier to use, they are also faster: switching from GDI+ to System.Windows.Media.Imaging reduced processing time to 50%, with an apparant significant lower CPU load and memory requirement. A complete example, including a unit test project that contains a test image which performs the completely hypothetical action of cutting a large 2048x2048 map file into 256x256 tiles ;-), is downloadable here. This project contains the following statement
Path.GetDirectoryNameAssembly.GetExecutingAssembly().Location
don't be intimidated by this, that's just a way to determine the full path of the current directory, i.e. the directory in which the unit test is running - you will find the resulting images there.

17 February 2009

Silverlight data binding the lazy way

Your typical business class utilizing data binding in Silverlight (and possibly WPF too, but I don't have any experience with that) look like this:
using System.ComponentModel;

namespace Dotnetbyexample
{
  public class Person : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    private string firstName;
    public string FirstName
    {
      get { return this.firstName; }
      set
      {
        this.firstName = value;
        this.NotifyPropertyChanged("FirstName");
      }
    }

    private string lastName;
    public string LastName
    {
      get { return this.lastName; }
      set
      {
        this.lastName = value;
        this.NotifyPropertyChanged("LastName");
      }
    }

    private string address;
    public string Address
    {
      get { return this.address; }
      set
      {
        this.address = value;
        this.NotifyPropertyChanged("Address");
      }
    }

    private string city;
    public string City
    {
      get { return this.city; }
      set
      {
        this.city = value;
        this.NotifyPropertyChanged("City");
      }
    }

    private string state;
    public string State
    {
      get { return this.state; }
      set
      {
        this.state = value;
        this.NotifyPropertyChanged("State");
      }
    }

    private string zip;
    public string Zip
    {
      get { return this.zip; }
      set
      {
        this.zip = value;
        this.NotifyPropertyChanged("Zip");
      }
    }

    public void NotifyPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}
Silverlight data binding rocks, for if you change the attribute, the listening GUI elements will update automatically, but what I particulary not like is the fact that the NotifyPropertyChanged method needs to be called with the name of the property as a string. Change the property name and the event does not work anymore. I created the following extension method
using System.ComponentModel;
using System.Diagnostics;

namespace Dotnetbyexample
{
  public static class INotifyPropertyChangedExtension
  {
    public static void NotifyPropertyChanged(
       this INotifyPropertyChanged npc, 
       PropertyChangedEventHandler PropertyChanged)
    {
      if (PropertyChanged != null)
      {
        string propertyName =
           new StackTrace().GetFrame(1).GetMethod().Name.Substring(4);

        PropertyChanged(npc, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}
which allows me to rewrite the business object as follows
using System.ComponentModel;

namespace Dotnetbyexample
{
  public class Person : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    private string firstName;
    public string FirstName
    {
      get { return this.firstName; }
      set
      {
        this.firstName = value;
        this.NotifyPropertyChanged(PropertyChanged);
      }
    }

    private string lastName;
    public string LastName
    {
      get { return this.lastName; }
      set
      {
        this.lastName = value;
        this.NotifyPropertyChanged(PropertyChanged);
      }
    }

    private string address;
    public string Address
    {
      get { return this.address; }
      set
      {
        this.address = value;
        this.NotifyPropertyChanged(PropertyChanged);
      }
    }

    private string city;
    public string City
    {
      get { return this.city; }
      set
      {
        this.city = value;
        this.NotifyPropertyChanged(PropertyChanged);
       }
    }

    private string state;
    public string State
    {
      get { return this.state; }
      set
      {
        this.state = value;
        this.NotifyPropertyChanged(PropertyChanged);
      }
    }

    private string zip;
    public string Zip
    {
      get { return this.zip; }
      set
      {
        this.zip = value;
        this.NotifyPropertyChanged(PropertyChanged);
      }
    }
  }
}
and presto: I got rid of the custom NotifyPropertyChanged method at the bottom of the class, and now the call to the extension method NotifyPropertyChanged is the same for every setter. No need to remember to change the string in the NotifyPropertyChanged when the property name changes - or when you copy the getter/setter from somewhere else ;-) Key to the whole trick is the quite unorthodox usage of the Stacktrace
new StackTrace().GetFrame(1).GetMethod().Name.Substring(4);
credits for this of course go to Rockford Lhotka with his CSLA framework - in the BusinessBase object of this framework I noticed this trick a year or so ago and suddenly I wondered if it would work in a Silverlight environment as well. Update: in the newest version of the CSLA framework the method using this trick -CanWriteProperty - is marked deprecated, and is replaced by a method CanWriteProperty(string) that takes the property name as an explicit string - so Lhotka is now swinging round to follow the PropertyChangedEventHandler.

16 December 2008

[Serializable] does not inherit (aka RTFM)

Of course, everybody knows that if you want to serialize an object, you need to decorate the class with the [Serializable] attribute. Right? Well, yes, and so do I, but I ran into a snag today: it is an attribute, not a property so it does not inherit. If you consider the following code
using System;

namespace demo
{
    [Serializable]
    public class BaseClass
    {
        public string AProperty { get; set; }
    }

    public class ChildClass : BaseClass
    {
        public string AnotherProperty { get; set; }
    }
}
you will find that Childclass will not serialize with BinaryFormatter, although its base class will. This is of course quite evident, but a more interesting gotcha occurs when you add a third class:
    [Serializable]
    public class ChildClass2 : ChildClass
    {
        public string FinalProperty { get; set; }
    }
This won't serialize either, because halfway up it's class hierarchy there's a non-serializable class. In plain vanilla .NET this will generate an "Failed to serialize. Reason: Type 'demo.ChildClass' in Assembly 'bla bla bla' is not marked as serializable", precisely pinpointing the problem. If it happens (as in my case) deep down inside a CSLA dataportal, all you get is an error message like
System.ServiceModel.CommunicationException: The underlying connection was closed: The connection was closed unexpectedly. ---> System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.
And you might spend quite some time finding out it is caused by a non-serializable class somewhere in your class hierarchy. So, check your attributes, folkes ;-) Or run FxCop (and read the warnings)

12 December 2008

Calling Oracle stored functions from ADO.NET

Die-hard Microsofties may be flabbergasted, but there are people out there using Oracle as a database in stead of SQLServer and - oh horror - are even daft enough to try to retrieve data from it using ADO.NET. But while Microsoft cranks out code samples for using SQLServer by the the truckload, those that are living in a hybrid environment may have a hard time finding actual working data access sample code. Like calling a stored function in Oracle and retrieving the value. Suppose whe have the following trivial stored function, created by my collegue Louis Ywema for unit testing purposes. It takes a numerical value and a string value and concatenates them with a hyphen between. Not quite the functionality you've been waiting for all your life but it proves the point
create function get_test  (p_parameter1 in number
                   ,p_parameter2 in varchar2)
return varchar2
is
   l_parameter1 number;
   l_parameter2 varchar2(1024);
begin
   l_parameter1 := p_parameter1;
   l_parameter2 := p_parameter2;
   return to_char(l_parameter1)||' - '||l_parameter2;
exception
   when others then
       return(sqlerrm);       
end get_test
You run this code in a database user that has CREATE PROCEDURE privileges Next, you define an Oracle connection in your connectionStrings section of your config file:
<connectionStrings>
  <add name="MYCONNECTION" 
    connectionString="Password=TEST;User ID=TEST;Data Source=JOOST;"
    providerName="System.Data.OracleClient" />
</connectionStrings>
I use a database JOOST with username TEST and password TEST Using raw ADO.NET code you can run the stored function like this
[TestFixture]
[Test(Description = "Stored function - Raw ADO.NET")]
public void TestStoredFunctionRaw()
{
  var myConnection = 
      ConfigurationManager.ConnectionStrings["MYCONNECTION"];
  using (var connection = 
      new OracleConnection(myConnection.ConnectionString))
  {
     connection.Open();
     using(var command = connection.CreateCommand() )
     {
       var p1 = new OracleParameter("p_parameter1", OracleType.Number);
       p1.Value = 1;
       command.Parameters.Add(p1);

       var p2 = new OracleParameter("p_parameter2", OracleType.VarChar);
       p2.Value = "Hello";
       command.Parameters.Add(p2);

       var retVal = new OracleParameter("returnvalue", OracleType.VarChar);
       retVal.Size = 1024;
       retVal.Direction = ParameterDirection.ReturnValue;
       command.Parameters.Add(retVal);

       command.CommandText = "get_test";
       command.CommandType = CommandType.StoredProcedure;
       command.ExecuteNonQuery();

       Assert.IsTrue(((string)retVal.Value) == "1 - Hello");
     }
  }
}
I would not recommend this to anyone but it proves the point. For real life situations, use the Enterprise Library and write your code like this
[Test(Description = "Stored function -  EL")]
public void TestStoredFunctionEntLib()
{
    Database Db = DatabaseFactory.CreateDatabase("MYCONNECTION");
    using (var cmd = Db.GetSqlStringCommand("get_test" ) )
    {
      Db.AddInParameter(cmd, "p_parameter1", DbType.VarNumeric, 1);
      Db.AddInParameter(cmd, "p_parameter2", DbType.String, "Hello");
      Db.AddParameter(cmd, "returnvalue", DbType.String,1024, 
        ParameterDirection.ReturnValue, 
        false, 0, 0, null, DataRowVersion.Default, null);

      cmd.CommandType = CommandType.StoredProcedure;
      Db.ExecuteNonQuery(cmd);
      Assert.IsTrue(((string) cmd.Parameters[2].Value) == "1 - Hello");
    }
}
Notice the "returnvalue" parameter - it has a ParameterDirection.ReturnValue and more importantly - it has a size. This is important: the default size of a parameter is 0, and if Oracle tries to write back te parameter value into the parameter you will get an error indicating so. In this example I use 1024, but you can set this to any size you need. In my production code I set it to 32K (32768) but I am not sure of the absolute maximum value. The crazy thing about this is, of course, there are situations where you cannot know the size of the return value. Your only option is to set is as high pas possible and hope for the best ;-) Complete test project downloadable here. This example still uses the May 2007 EntLib 3.1, by the way.

04 December 2008

Converting colors from RGB to HTML and back

A very short one this time: it turns out to be pretty easy to convert a RGB color to a HTML color and back. This may come handy when (like me) you are using configuration files in which colors for map features are specified in RGB. Add a reference to System.Drawing.dll and a "using System.Drawing" to your class and you can use the following code:
Color rgbColor = Color.FromArgb(255, 0, 0);
string HTMLColor = ColorTranslator.ToHtml(rgbColor);
Color rgbColor2 = ColorTranslator.FromHtml(HTMLColor);
Color rgbColor3 = ColorTranslator.FromHtml("Fuchsia");

 Console.WriteLine(HTMLColor);
 Console.WriteLine(string.Format("{0},{1},{2}",
     rgbColor2.R, rgbColor2.G, rgbColor2.B));
 Console.WriteLine(string.Format("{0},{1},{2}",
     rgbColor3.R, rgbColor3.G, rgbColor3.B));
this wil output the following: #FF0000 255,0,0 255,0,255 I translated RGB red to HTML red, and back. For an encore, I demonstrated the fact that named colors are translated into RGB as well.

29 November 2008

Writing a simple HTTP proxy using WCF

I ran into a situation with the following network topology: The intranet server served PDF documents via IIS, but was only accessible from the WCF server - which, for technical and political reasons, could not run in IIS but had to be a Windows Managed service that hosted a WCF service. Yet I needed to be able to download files from the intranet server via an ordinary URL. It turns out that you can write a WCF service mimicking a HTTP server pretty easily. If you can utilize .NET 3.5SP1, that is. 1. Data contract There are few key points to the contract:
  • Make a reference to System.ServiceModel.Web.dll
  • Add a "using System.ServiceModel.Web"
  • Define a method returning a Stream
  • Decorate that method with a WebGet attribute
Your datacontract could look like this:
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace ProxyService
{
    /// 
    /// Service contract for a proxy that forwards a http request
    [ServiceContract]
    public interface IHttpProxy
    {
        [OperationContract, WebGet]
        Stream GetProxyRequest(string target);
    }
}
2. Implementation class This is basically a modified version of a solution based upon an ASP.NET page I described before.
using System.IO;
using System.Net;
using System.ServiceModel.Web;
using System.Web;

namespace ProxyService
{
    /// 
    /// A proxy that forwards a http request
    /// 
    public class HttpProxy : IHttpProxy
    {
        public Stream GetProxyRequest(string target)
        {
            var urlToLoadFrom = HttpUtility.UrlDecode(target);
            HttpWebRequest webRequest = 
               HttpWebRequest.Create(urlToLoadFrom) as HttpWebRequest;

            // Important! Keeps the request from blocking after the first
            // time!
            webRequest.KeepAlive = false;
            webRequest.Credentials = CredentialCache.DefaultCredentials;
            using (var backendResponse = 
              (HttpWebResponse)webRequest.GetResponse())
            {
                using (var receiveStream = 
                  backendResponse.GetResponseStream())
                {
                    var ms = new MemoryStream();
                    var response = 
                      WebOperationContext.Current.OutgoingResponse;
                    // Copy headers
                    // Check if header contains a contenth-lenght since IE
                    // goes bananas if this is missing
                    bool contentLenghtFound = false;
                    foreach (string header in backendResponse.Headers)
                    {
                        if (string.Compare(header, 
                          "CONTENT-LENGTH", true) == 0)
                        { 
                          contentLenghtFound = true;
                        }
                        response.Headers.Add(header, 
                          backendResponse.Headers[header]);
                    }

                    // Copy contents
                    var buff = new byte[1024];
                    var length = 0;
                    int bytes;
                    while ((bytes = receiveStream.Read(buff, 0, 1024)) > 0)
                    {
                        length += bytes;
                        ms.Write(buff, 0, bytes);
                    }

                    // Add contentlength if it is missing
                    if (!contentLenghtFound) response.ContentLength = length;

                    // Set the stream to the start
                    ms.Position = 0;
                    return ms;
                }
            }
        }
    }
}
3. Configuration settings To get it all to work, you will need some configuration settings in the App.config of the hosting application:
<system.serviceModel>
  <services>
    <service name="ProxyService.HttpProxy" >
      <endpoint address="" binding="webHttpBinding"
                behaviorConfiguration="WebHttpBehavior"
                contract="ProxyService.IHttpProxy" >
      </endpoint>

      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:8002/ProxyService.HttpProxy" />
        </baseAddresses>
      </host>
    </service>

  </services>
  <behaviors>
    <endpointBehaviors>
      <behavior name="WebHttpBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>
Notice the endpointBehaviors section: this is really important to get the stuff to work. 4. Using the proxy You can now simply enter "http://yourhost:8002/ProxyService.HttpProxy/GetProxyRequest?target=urlencodedurl" in your browser, and the WebGet attributes will automatically make the GetProxyRequest method get called with the value of target as value for the target parameter. The code of the proxy expects target to contain an URLEncoded URL (use HttpUtility.UrlEncode to encode the actual url to something that can be passed as a parameter on an URL). Concluding remarks The magic of the WebGet attribute is barely scratched by this example, but it makes creating REST services with WCF a real piece of cake. I am not sure if it was intended to be used this way, but it sure works like hell ;-)