August 2006 - Posts - Rudolf Henning

August 2006 - Posts

Ever wished you can make something 'useful' of your browser startup page? Then have a look at http://www.tiddlywiki.com/

Done in pure Javascript it allows you to create a completely customizable 'home' page that requires no server side for processing and storing your 'stuff'. In stead of having to create a plain html page which you maintain with notepad or something this thing maintains itself (literally). Any changes are saved back to the actual html document.

Apparently there is also ways to use some of the same functionality to update the page if it is hosted on a web server - haven't check out the details yet.

 

 

with no comments
Filed under:

Perhaps not entirely accurate but funny how some of the following seems true.

What does your browser reveal about you?

So, who's still using IE 5? Stick out tongue

 

with no comments
Filed under:

This is a cool way to browse the web while your bosswould think you are working in Microsoft Word....

http://www.workfriendly.net/ 

Now go look busy...

with no comments
Filed under:

If you work a lot with your development machine (like most developer should...) you often find ways to ease the daily stuff you have to do. Managing your machine is one of those things that just becomes a big pain if its difficult and tedious. Take launching IIS admin (the mmc snap-in) with which you manage your web server. One way would be by just copying the shortcut to the desktop but that just takes up valuable 'real-estate' on your desktop. Even adding it to the quick launch toolbar eventually means cluttering of too many utilities. So I decided to put another shortcut at a place where it should make more sense - My Computer context menu.

Do enable this you simply import(merge) the following reg file:

------------------------------------------------------------ 

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\shell\IISManage]
@="IIS admin"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\shell\IISManage\command]
@=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,73,00,79,00,73,\
  00,74,00,65,00,6d,00,33,00,32,00,5c,00,6d,00,6d,00,63,00,2e,00,65,00,78,00,\
  65,00,20,00,2f,00,73,00,20,00,25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,\
  00,6f,00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,\
  32,00,5c,00,69,00,6e,00,65,00,74,00,73,00,72,00,76,00,5c,00,69,00,69,00,73,\
  00,2e,00,6d,00,73,00,63,00,00,00

 ------------------------------------------------------------

with no comments
Filed under:

I still remember learning Turbo Pascal as varsity (seems ages ago). I loved it then and wrote tons of little programs for myself to play with. Then I got accelerated into the 'real' world... but let’s not go there now.

It seems Borland might be up to some tricks or the pressure from Microsoft Express line of development tools might be getting to them. They have announced the released of a couple of Turbo Explorer editions which is free plus some Professional editions for a charge.

http://www.pcmag.com/article2/0,1895,2000232,00.asp 

 

 

with no comments
Filed under:

A while ago I needed a quick way to sort a generic collection for testing purposes. I then made a coding challenge on SaDev and with the help of one other member (ratty) got a class that did what I wanted. With this new collection class you can make any Generic collection and then sort on any property by name.

using System;
using System.Collections.Generic;
using System.Reflection;

public class SortedCollection<T> : List<T>
    {
        public void AdvancedSort(string propertyName)
        {
            this.Sort(delegate(T x, T y) { return compareObjects(x, y, propertyName); });
        }

        /// <summary>
        /// Compare two objects based on a common public Property name.
        /// Note: the objects do not have to be the same type, but the fields do!
        /// Thanks to ratty (sadev)
        /// </summary>
        private static int compareObjects(T x, T y, string property)
        {
            // Use reflection to find the matching fields, then compare them generically
            PropertyInfo prop1 = x.GetType().GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
            if (prop1 == null)
                throw new Exception("Unknown property '" + property + "' for comparison in class '" + x.GetType().Name + "'");
            PropertyInfo prop2 = y.GetType().GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
            if (prop2 == null)
                throw new Exception("Unknown property '" + property + "' for comparison in class '" + y.GetType().Name + "'");
            object c1 = prop1.GetValue(x, null);
            object c2 = prop2.GetValue(y, null);
            // check if the fields are comparable
            if (!(c1 is IComparable && c2 is IComparable))
                throw new Exception("Entered objects are not comparable");
            return ((IComparable)c1).CompareTo((IComparable)c2);
        }
    }

 

As you can see through a mixture of Generics, Anonymous methods and Reflection this is possible and works quite well. There will be limitations as the list gets bigger - because of all the reflection done at run-time.

An example of how it can be used:

class SomeClass
{

    private string someValue;
        public string SomeValue
        {
            get { return someValue; }
            set { someValue= value; }
        } 

SortedCollection<SomeClass> list = new SortedCollection<SomeClass>(); 

...

list.AdvancedSort("SomeValue");

This class just shows how powerful and useful Generics and anonymous methods could be.

 [Update: It had to come. The need arrived to 'invert' the sorting order and the way to solve this is by modifying the 'AdvancedSort' method.

public void AdvancedSort(string propertyName)
{
    AdvancedSort(propertyName, true);
}
public void AdvancedSort(string propertyName, bool sortOrderInverted)
{
    if (! sortOrderInverted)
        this.Sort(delegate(T x, T y) { return compareObjects(x, y, propertyName); });
    else
        this.Sort(delegate(T x, T y) { return compareObjects(y, x, propertyName); });
}

with no comments
Filed under:

Although it is probably better for a source system to produce things like sequence or counter numbers I did found an easy and neat way to implement this in BizTalk (2004) that is not resource intensive. When the requirement first came up I did a search on the net and found a solution that is based on an orchestration, but this means that handing real big volumes of files could become a problem i.e. like when you receive batches of files over 1000 a time.

The solution I came up with is based on creating a custom pipeline component which access the meta data of a message as it is being processed through the outgoing pipeline. Perhaps it is a bit of a hack but it seems to work renaming the promoted property value for "ReceivedFileName". This value can then be used in the file send port as a macro for naming the file.

Inside the pipeline component I got some code doing a simple database lookup / update that returns the next sequence number available. The stored procedure must be carefully written to not cause heavy table locks etc. to ensure it can handle volumes (remember BizTalk is multithreaded and optimized to handle volumes). Inside the stored proc you can basically do whatever you like as long as it execute very fast.

The advantages of this solution is that you do not have to build big orchestrations to accomplish this, it operates very efficiently and allows you to do custom stuff with the sequence number. I tried making it fairly generic but it can be extended quite easily to do various other things. Because the component requires database access and I don't want to hard code the connection string in the component or the send pipe that use it I added a property to specify a config value key. This config key/value can either be stored in the BizTalk exe.config or the machine.config. This is another reason I would have liked dll's to have had its own config files..

 So without much further ado.. here is some source code:

The FileRenameCounter class custom Send pipeline component.

[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[System.Runtime.InteropServices.Guid("some guid here")]
[ComponentCategory(CategoryTypes.CATID_Encoder)]
public class FileRenameCounter : Microsoft.BizTalk.Component.Interop.IComponent, IBaseComponent, IPersistPropertyBag, IComponentUI
{
   .. all the other stuff as generated by the wizard

   private string _StoredProcedure; //variable names as generated by wizard...yes I know it sucks to use VB conventions
   public string StoredProcedure
   {
      get
      {
         return _StoredProcedure;
      }
      set
      {
         _StoredProcedure = value;
      }
   } 

  private string _ConnectionStringConfigKey;
  public string ConnectionStringConfigKey
  {
     get
     {
        return _ConnectionStringConfigKey;
     }
     set
     {
        _ConnectionStringConfigKey = value;
     }
  }

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
   object oldFileName = string.Empty;
   IBaseMessageContext context = inmsg.Context;
   oldFileName = context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties");
   if (oldFileName != null)
   {
      string newFileName = GetNewFilename((string)oldFileName);
      context.Write("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties", newFileName);
   }
   return inmsg;
}

private string GetNewFilename(string oldFileName)
{
   string connectionString;
   FileRenameCounterDAL fileRenameCounterDAL = new FileRenameCounterDAL();
   System.Configuration.AppSettingsReader appsettings = new System.Configuration.AppSettingsReader();
   connectionString = appsettings.GetValue("FileRenameCunterConnectionString", typeof(string)).ToString();
  
   fileRenameCounterDAL.ConnectionString = connectionString;
   return System.IO.Path.GetFileNameWithoutExtension(oldFileName) +   fileRenameCounterDAL.GetNextCounterValue(_StoredProcedure, oldFileName) +   System.IO.Path.GetExtension(oldFileName);
  }

The stored procedure I use looks like this (this is just a sample)

CREATE PROCEDURE RegisterFile
  @FileName varchar(1024)
AS
  SET Nocount on
  SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

  INSERT ProcessedFile
    ( [FileName] )
  VALUES (@FileName)

 SELECT top 1 FileID
  FROM  ProcessedFile
  WHERE  [FileName] =  @FileName
  ORDER BY ProcessDate desc
GO

And the table (also just a sample)

CREATE TABLE [dbo].[ProcessedFile] (
    [FileID] [int] IDENTITY (1, 1) NOT NULL ,
    [FileName] [varchar] (1024) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    [ProcessDate] [datetime] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[ProcessedFile] ADD
    CONSTRAINT [DF_ProcessedFile_ProcessDate] DEFAULT (getdate()) FOR [ProcessDate],
    CONSTRAINT [PK_ProcessedFile] PRIMARY KEY  CLUSTERED
    (
        [FileID]
    )  ON [PRIMARY]
GO

Using this component requires a simple Send pipeline with this component in the 'Encode' section. Then you can simply set up a send port and specify this pipeline as the one to use.

I've tested it with batches of 1000 files that completes in about 40 seconds (on my little dev box).

Lastly I have to re-iterate that the best solution for this type of requirement is that the source system generates the sequence numbers and not BizTalk. However, in some cases you might have an existing source system that cannot be modified thus forcing you to have the sequence numbers generated later.

If you are interested in the full source code let me know. I still need to clean up the test project (as I've been playing around with it alot ;) ) 

with no comments
Filed under:

There may have been a time when programming was considered just a simple process of writing (or typing more correctly) some source code. Today if you even attempt to just write a 'simple'  thing you have to consider dozens of things that are not directly related to writing source code. Things like performance, security, user preferences, office politics, hell even the tea lady that has got something to say by times...

The 'art' part of programming is in keeping everyone happy and yourself sane (and employed). Often the latter part is the more difficult one...

Well, these were just some quick thoughts on the subject before they disappeared into one of my 'forget' holes in my head.

Now where is that system spec that was written on a piece of paper the size of a toilet paper block?... The one that says loading 6000 items into a drop-down box on a web page...

with no comments
Filed under: