NullifyNetwork

The blog and home page of Simon Soanes
Skip to content
[ Log On ]

Archive - Historical Articles

You are viewing records from 06/12/2004 15:00:08 to 05/13/2005 07:51:40. I'll be adding support for selecting a date range in future.

Apologies for the lack of posting, but crunch mode at work whilst approaching beta has stopped me having time.  I'll probably get some more posted when it's over. Permalink 

This is good fun :) - a DHTML lemmings remake!

http://193.151.73.87/games/lemmings/index.html

It works on IE and Opera, so I have no doubt it'll work on Firefox/Mozilla.

Permalink 

[ Taken from my post at the ms forums here: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=1014 ]

This is a bit bodged but I just hashed it together to see how easy it would be.  I thought back and could have just iterated over chararray, but it works which is what counts :D

/// <summary>
///
Represents a paragraph in English
///
</summary>
public
abstract class Paragraph
{
///
<summary>
///
Convert a string in arbitrary case to English sentence capitalisation.
///
</summary>
/// <param name="text">The text to convert
</param>
/// <returns>The paragraph of text
</returns>
public
static string ToSentenceCase(string text)
{
string
temporary = text.ToLower();
string
result = "";
while
(temporary.Length>0)
{
string
[] splitTemporary = splitAtFirstSentence(temporary);
temporary = splitTemporary[1];
if
(splitTemporary[0].Length>0)
{
result += capitaliseSentence(splitTemporary[0]);
}
else
{
result += capitaliseSentence(splitTemporary[1]);
temporary =
""
;
}
}
return
result;
}

private static string capitaliseSentence(string sentence)
{
string
result = "";
while
(sentence[0]==' ')
{
sentence = sentence.Remove(0,1);
result+=
" "
;
}
if
(sentence.Length>0)
{
result += sentence.TrimStart().Substring(0, 1).ToUpper();
result += sentence.TrimStart().Substring(1, sentence.TrimStart().Length-1);
}
return
result;
}

private static string[] splitAtFirstSentence(string text)
{
//these are the characters to start a new sentence after
int
lastChar = text.IndexOfAny(new
char[] {'.', ':', '\\', '\r', '!', '?'})+1;
if
(lastChar==1)
{
lastChar = 0;
}
return
new string[] { text.Substring(0, lastChar), text.Substring(lastChar, text.Length-lastChar) };
}
}

Permalink 

[posted by me on the new Microsoft Forums at http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=1266 ]

ProcessStartInfo pi = new ProcessStartInfo("cmd.exe", "/c dir");
pi.WindowStyle = ProcessWindowStyle.Hidden;
pi.RedirectStandardOutput =
true
;
pi.UseShellExecute =
false
;
Process p = Process.Start(pi);
p.WaitForExit();
p.Start();
TextReader t = p.StandardOutput;
MessageBox.Show(t.ReadToEnd());

Permalink 

A colleague of mine at work was having some trouble with multithreading this morning and I suggested using asynchronous delegates (a delegate - something you can make do something else, in .NET this can be used as a form of trigger for starting any number of other methods that take and return the same parameters as it uses - that runs its methods in another thread).  This got me thinking so I decided to do a quick tutorial for anyone else who has't yet encountered this way of doing multithreading!

This is a short sharp example, and can be created in a simple form.  Remember not to try to update the form from the method being run by the delegate - if you want to do this you need to run a method that checks if InvokeRequired is true, then runs Invoke(myMethodsOwnName, new object {myFirstParameter, mySecondParameter, andSoOn}) if it is true, or does whatever UI editing is needed if false - so it is calling itself in the context of the user interface.

Anyway, on with the example!

/// <summary>
///
A button on the form
///
</summary>
private
void button1_Click(object sender, System.EventArgs e)
{
   delegateInstance = new
ExampleDelegate(beginThink);
   d.BeginInvoke(5, new
AsyncCallback(finished), null);
}

This is where the program runs, a simple button that can be pressed.  We want to do something CPU intensive and blocking in here but instead we create an instance of a delegate and use the BeginInvoke method, the methods parameters come first (in this case 5) and then the callback method to run, and null for the object state.

/// <summary>
///
An instance of the delegate used to call a method asynchronously
///
</summary>
private
ExampleDelegate delegateInstance;

/// <summary>
///
The example delegate
///
</summary>
private
delegate string ExampleDelegate(int param);

/// <summary>
///
The example method that would block the user interface
///
</summary>
/// <param name="workOn">Number of seconds to block for
</param>
/// <returns>Some string
</returns>
private
string beginThink(int workOn)
{
   Thread.Sleep(workOn*1000);
   return
"Done";
}

This is our ficticious CPU intensive action, in this case we'll just block the thread by seeping for workOn seconds.

/// <summary>
///
The method that is called when work is done
///
</summary>
/// <param name="results">The results of the work
</param>
private
void finished(IAsyncResult results)
{
   MessageBox.Show(delegateInstance.EndInvoke(results));
}

And this is run when the asynchronous delegate is completed.  EndInvoke automatically return the same type as the delegate, (a string) which makes this nice and easy.

Permalink 

Two days ago I got my new P7010 laptop, although it's hardly large enough to be called a laptop with a tiny 10.6" screen and being light enough to use with one hand whilst holding it with the other.

This is a review, or maybe a quick pass over it.  I'm typing it on it, but I won't be doing any serious coding on it due to some oddities with the keyboard layout (cursor keys, home and end which I regularly use are all one thing and need to use the fn key, which is in the wrong place being between ctrl and windows rather than on the far left.  And the delete key is in the top right.  I'll upload some pitctures to my public photo album shortly.)

There are several things nobody says when they talk about this laptop, and I wondered whether I should buy it because of this.  I'm very glad I did.

Firstly, it runs 3D games very well - if you use lower end settings.  This is to be expected with an Intel extreme graphics chip in it, and it's a tradeoff you need to make for the small size and long battery life.  I've yet to try Half-Life 2, but will update this post if I get a chance - probably on the weekend.

The 1.1Ghz processor easily beats a P4 3Ghz processor in appearing to be fast, it may not when encoding an MP3, or some other maths intensive task but it seems highly responsive - infact it appears as responsive as my Opteron workstation when using applications (although the drive is slower, however this is to be expected 10,000 rpm is physically a lot faster than 4200 rpm!).

Next, the screen everyone says is too high res for the size IS too high res for the size - but I've noticed that after using it for a short while I have easily gotten used to it.  Maybe support for 1024x640 would have been better than 1280x768, but this is at least future proofed for when Windows is fully vector based and will scale.  The screen is extremely crisp, clear and bright, though reflective and needing cleaning to prevent dust accumulating.  The screen is perfect for DVD's and videos - anything that scales..

It also has a slew of standard and not so standard features: Wireless, cd/dvd drive (in such a small laptop!) sd/mmc/memory stick reader, compact flash and seperate PCMCIA slot, two USB ports, video out, LAN, international modem, svideo and firewire.  An impressive battery life (so far tested to 6 hours 50 minutes real world use, with wifi on, without the second battery and with the screen not on the lowest brightness) rounds it off.  An impressive selection of modular options from Fujitsu Siements also makes this a very versatile device.

Missing features: GPRS/GSM, Camera, Bluetooth, serial and parallel ports, rear connectors (everything is conveniently on the sides), a top catch (although it seems to be sprung with some kind of mechanism that holds it shut and closes it quickly, but allows the screen to move freely to any angle), and dedicated graphics memory and card.

Overall I'm very impressed.  Apart from bluetooth most of the features are either not neded or an acceptable tradeoff for a device this small, the absence of bluetooth however should have meant the necessity of GPRS/GSM in a portable device - yet I am fine with wifi for the places I go.  As a large (book sized) PDA it serves well, as something to take notes on it beats a pda hands down - as you can see from this having been typed on it (I have no trouble touch typing on it).  As something to code on, we shall see.  As an entertainment device - well, you can watch dvd's, listen to music and play games - what more do you want?

I don't recommend anyone try to make such a small device their primary laptop or even worse primary computer without an external screen and keyboard/mouse however if you want small and portable because you travel or just don't want to carry a full laptop then this is the machine for you.

Permalink 

I've been looking for a good .NET profiler and always been hit by large price tags, bloated software and general failure.

So, I was happy to discover the person that made NAnt also makes NProf!  http://nprof.sourceforge.net/Site/SiteHomeNews.html

I had to delete regasm.exe from his archive as it throws an exception for some reason, but when using the one on my system it registered fine and is now working - happily integrated into Visual Studio .NET :)

Permalink 

Mere minutes after posting about VSA I notice a post on developer fusion by Mark Belles that is MUCH better at describing Microsoft.VSA - I suggest if your interest is peaked by my sample code you go have a look at his article!

Permalink 

Have you ever wanted to be able to add scripting to your application?  So your users can write a script and you can have it run inside it, adding menus, etc. - like Microsoft Visual Basic for Applications allows in Office.

This is a preliminary article, I'll try to rewrite this but I just took a 20 minute break from work (need to have something done for tomorrow - so yes, still working at 10PM!  GRR) and finally managed to get scripting using Microsoft.VSA working from a C# application.  Apologies for the lack of tabs in the formatting and lack of explanation.

This is missing the ability to access anything in the running application - you need to register a global item (in the same way as code items and references are added) to do that - then it is exposed as an object inside the environment running the script.

Add references to Microsoft.VisualBasic.Vsa and Microsoft.Vsa (when I repost I'll be using JScript.NET - never fear!) and add the following using clauses:

using

System.Reflection;

using

Microsoft.Vsa;

using

Microsoft.Win32;

And then add the following code to a button or similar (with a textbox to enter your script in) - this will create a scripting engine object, then run your script inside it.  The best test is to show a message using MessageBox.Show(""); (remember though, it's VB!)

ScriptEngine eng = new ScriptEngine();
eng.Start();
IVsaCodeItem c = eng.CreateCodeItem(
"ScriptItem");
c.SourceText = textBox1.Text; //Where this is a simple vb.net script with a class called Script and a Sub called Main
eng.Run();

And now, the main code chunk snippet that is the scripting engine:

 

public class ScriptEngine : IVsaSite
{
private IVsaEngine Engine;
public ScriptEngine()
{
Start();
}

 

public void Start()
{
try
{
Engine =
new Microsoft.VisualBasic.Vsa.VsaEngine();
Engine.RootMoniker =
"myapp://net.nullify.www/ScriptEngine";
Engine.Name =
"vsaEngine";
Engine.RootNamespace =
"VsaEngine";
Engine.Site =
this;
Engine.InitNew();
CreateReference(
"Mscorlib.dll");
CreateReference(
"System.dll");
CreateReference(
"System.Windows.Forms.dll");
CreateReference(
"System.Data.dll");
CreateReference(
"System.Drawing.dll");
CreateReference(
"System.XML.dll");
}
catch (VsaException ex)
{
MessageBox.Show(
"Scripting engine error: "+ex.Message);
}
}

 

public IVsaReferenceItem CreateReference(string assemblyName)
{
IVsaReferenceItem item = (IVsaReferenceItem)Engine.Items.CreateItem(assemblyName, VsaItemType.Reference, VsaItemFlag.None);
item.AssemblyName = assemblyName;
return item;
}

 

public IVsaCodeItem CreateCodeItem(string itemName)
{
try
{
IVsaCodeItem item = (IVsaCodeItem)Engine.Items.CreateItem(itemName, VsaItemType.Code, VsaItemFlag.Class);
return item;
}
catch (VsaException ex)
{
MessageBox.Show(
"Problem creating the code item: "+ex.Message);
}
return null;
}

 

public void Run()
{
if (Engine.Compile())
{
Engine.Run();
Type type = Engine.Assembly.GetType(
"VsaEngine.Script");
MethodInfo method = type.GetMethod(
"Main");
method.Invoke(
null, null);
}
}

#region

IVsaSite Members

 

public object GetEventSourceInstance(string itemName, string eventSourceName)
{
// TODO: Add ScriptEngine.GetEventSourceInstance implementation
return this;
}

 

public object GetGlobalInstance(string name)
{
// TODO: Add ScriptEngine.GetGlobalInstance implementation
return null;
}

 

public void Notify(string notify, object info)
{
// TODO: Add ScriptEngine.Notify implementation
}

 

public bool OnCompilerError(IVsaError error)
{
MessageBox.Show(
"["+error.Line+"] Compiler error: "+error.Description);
return true;
}

 

public void GetCompiledState(out byte[] pe, out byte[] debugInfo)
{
// TODO: Add ScriptEngine.GetCompiledState implementation
pe = null;
debugInfo =
null;
}

#endregion

}

And finally to test this you can use the following code:

imports System
imports System.Diagnostics

module Script
sub Main()
MessageBox.Show("Boo")
end sub
end module

Permalink  2 Comments 

Robert Scoble is once again on his high horse about how RSS is amazing, comparing it to GUI versus CLI without looking at how primitive RSS itself is.  I propose it is around the other way, and that there is a successor for RSS out there.

RSS and ATOM as they are today WILL become extinct - or at least as limited as CLI's are today, with a small following; syndication and a standard way of reading content from a site without visiting the URI in a browser are going to be around for ages - I have no doubt about this.

The key is that someone needs to define a standard (e.g. - based on SOAP since we already happen to have it!) to query a 'feed' (now, we can term it a web service) for:

  • New entries without content since a previous point in time
  • New entries with content since a previous point in time
  • All entries ever
  • A specific web log entry
  • Comments for an entry
  • All comments since a point in time
  • All comments ever
  • An entry with comments at the same time
  • Indicating you linked to a post or comment
  • Posting a comment
  • And to 'subscribe' where you are e-mailed or IM'd (or using msn alerts, or Jabber alerts or whatever) when there is an update.

It is inevitable, RSS uses too much bandwidth and gives duplicated content only when you request it which means you need to keep checking back (even if you get a HTTP message to say it has't changed).

A web service could make available only the necessary information in a smart way, it could track and push information in the background to notify when your aggregator needs to look at your RSS/ATOM data for new entries, and it could allow a full integration of the site with the aggregator for comments.

Robert needs to look forward, not back...

Permalink 

http://me.sphere.pl/indexen.htm

MoonEdit is a multi user text editor, it lets two (or more) people simultaneously edit a single file, with multiple cursors, entry points and near real time collaboration.

I've been waiting for something like this for a while, after posting about it first, then a year or two later seeing SubEthaEdit for the Mac.  Hopefully someone (http://docsynch.sourceforge.net/) will come up with a plugin for Visual Studio.

(Links curtesy of ntk.net)

Permalink 

I've noticed some google oddness, a lot of sites have suddenly dropped quite low in rankings. My DeveloperFusion profile page is now higher than my CV and this site!

Robert Scoble is now the SECOND Robert. No other search engine places THAT much weight on the Scobleizer.

And when searching for my current employer, Capita, a partner of theirs comes up first!

I have been trusting gigablast and even the new MSN search more than google recently, and I can't quite be sure what google have done to skew their current index.

(At least, on the search engine front. I am very impressed with some of google's current projects.)

Permalink  1 Comments 

This is some code I wrote a little while back as an example OR mapper.  When inheriting from BaseDataDynamicEntity you can use the attribute [DataDynamic(“Name”)] to indicate the field name in the database and then use the class below to fetch data from the database or update it with any changes.

 

This is just an example though and doesn’t do the updating – but instead returns an array of string that can be used to look at what’s in the object now.  Return a set of SqlParameter’s and plug it into a stored procedure for a working example.

 

      public abstract class BaseDataDynamicEntity

      {

            /// <summary>

            /// An attribute to use to work out which properties have names that are in the database

            /// </summary>

            public class DataDynamic : Attribute

            {

                  public DataDynamic(string fieldName)

                  {

                        _fieldName = fieldName;

                  }

                  /// <summary>

                  /// The name of the field in the database

                  /// </summary>

                  public string FieldName

                  {

                        get

                        {

                              return _fieldName;

                        }

                  }

                  private string _fieldName = "";

            }

 

            /// <summary>

            /// Return a set of properties on this class as a demonstration of what is possible

            /// </summary>

            /// <returns></returns>

            public string[] ListDataProperties()

            {

                  Type t = this.GetType();

                  PropertyInfo[] p = t.GetProperties();

                  ArrayList properties = new ArrayList();

                  foreach (PropertyInfo pi in p)

                  {

                        if (pi.IsDefined(typeof(DataDynamic), true))

                        {

                              properties.Add(pi.Name+": "+pi.GetValue(this, null).ToString()); //could instead write these out to some parameters.

                        }

                  }

                  string[] values = new string[properties.Count];

                  properties.CopyTo(values);

                  return values;

            }

 

            /// <summary>

            /// Given an SqlDataReader from ExecuteReader, fetch a set of data and use it to fill the child objects properties

            /// </summary>

            /// <param name="dr"></param>

            public void SetDataProperties(SqlDataReader dr)

            {

                  while (dr.Read())

                  {

                        for (int i = 0; i<dr.FieldCount; i++)

                        {

                              setProperty(dr.GetName(i), dr.GetValue(i));

                        }

                  }

                  dr.Close();

            }

 

            private void setProperty(string name, object data)

            {

                  Type t = this.GetType();

                  PropertyInfo[] p = t.GetProperties();

                  foreach (PropertyInfo pi in p)

                  {

                        if (pi.IsDefined(typeof(DataDynamic), true)&&pi.CanWrite)

                        {

                              object[] fields = pi.GetCustomAttributes(typeof(DataDynamic), true);

                              foreach (DataDynamic d in fields)

                              {

                                    if (d.FieldName == name)

                                    {

                                          pi.SetValue(this, data, null);

                                    }

                              }

                             

                        }

                  }

            }

      }

 

And to use this, you do something like:

 

      public class NewsArticle: BaseDataDynamicEntity

      {

            private int _id = 5;

            /// <summary>

            /// The Id in the database

            /// </summary>

            [DataDynamic("id")]

            public int Id

            {

                  get

                  {

                        return _id;

                  }

                  set

                  {

                        _id = value;

                  }

            }

 

            private string _name = "Demo object";

            /// <summary>

            /// The name in the database

            /// </summary>

            [DataDynamic("subject")]

            public string Name

            {

                  get

                  {

                        return _name;

                  }

                  set

                  {

                        _name = value;

                  }

            }

      }

 

Which makes populating it as easy as:

 

SqlConnection sq = new SqlConnection("Data Source=(local);InitialCatalog=nullifydb;Integrated Security=SSPI;");

      sq.Open();

      SqlCommand sc = sq.CreateCommand();

      sc.CommandText = "SELECT TOP 1 * FROM newsarticle";

NewsArticle n = new NewsArticle();

      n.SetDataProperties(sc.ExecuteReader());

      sq.Close();

 

Obviously this is just an example, and you would want to use a DAL of some sort to do the data extraction, but integrating the DAL with the above technique should be fairly easy.

Permalink 

This is something I posted to a mailing list in response to a question, but since posting it I've also been asked some questions which it answers - so, here is a VERY quick rundown of DNS:

> I basically need:

>

> (a) An overview of all the bits in the process – so I know I haven’t

> missed something obvious!

DNS is a tiered, cached method of querying some form of data, not necessarily a name, not necessarily an IP, not necessarily a text record, location, what the router for a network is, what the Kerberos/LDAP servers for a domain are, etc.

It uses the format:

Name dot

To distinguish a part, therefore (taking my own domain as an example) it is not really:

Nullify.net

But instead:

Nullify.net.

However the last dot is commonly left off for convenience incorrectly.  One or more domains controlled as a single entity on a server is called a 'zone'.

The bits that make up DNS from a practical standpoint consist of:

- A resolver

- A cache

- An authoritative server

The resolver is what exists on every persons computer, and on the ISP's nameservers along with a cache.  The resolver requests from the default DNS servers for the current dns 'zone' any desired records - in the case of a site that is in the root zone, or wants to query the root set of DNS servers there are a set of root servers, located at root-servers.net.  These can be extracted using dig, and have always stayed at the same IP - although one of these servers got a new multicast IP a short while ago.  Once a result (or NXDOMAIN, indicating there isn't a result) is retrieved - it is stored in the cache along with it's time to live (ttl).

The cache is the reason a small number of servers can support the whole Internet (obviously there's a lot behind the scenes, but the point still holds).  The vast majority of traffic is handled by the caches at every stage.  There will commonly be as many as four caches between an authoritative nameserver and a client.  The TTL maintains how long these hold a record of those results, and this is why DNS changes take so long.  The exact same cache is also used on a secondary nameserver, but rather than the TTL for records, the TTL for the zone itself is used.

An authoritative nameserver is a server that knows something itself.  It responds with a particular record for a particular domain - assuming anyone asks it.  There are both master and slave servers - a master holds the file that actually stores the data, the slave stores it in memory and relies on the TTL for the zone itself to decide how long it is authoritative.  The slave uses the zones serial number to decide whether a change has been made, and refreshes every time the refresh property of the SOA record for a zone has been expired.

>

> (b) An idea of how to set up the Windows Server as the primary nameserver

> (not sure if this is a good idea)

For windows you just create a zone and create the desired records.  From then on it will answer as a nameserver and can be queried by a machine looking at it as the default nameserver, or using nslookup/dig with it set as the default.

You then need to point a server on the internet for the domain you are adding a record to (say, net. Or com.!) to think it is the nameserver for a domain, and you require either an out of zone A record for it, or a glue record for it so that the IP of your own server can be resolved in order to go query it for the details of your domain!

To simplify this, for my domain I have a primary nameserver xerxes.nullify.net. at 2002:4262:b24a::4262:b24a and 66.98.178.74

This means that in order for xerxes to host nullify.net, the nameservers for net. Need to also contain both AAAA and A records for it.  A records resolve to a host.  (AAAA is ipv6, which you don't need to worry about yet).  You should request these records are created in advance for ALL nameservers that do not already have glue records.  The contact for the netblock the servers are hosted in may be contacted by some TLD providers, but net. And com. don't do this.

Once you have glue records that have propagated to all the servers for the zone they are in, you need to ask them to delegate a hostname for you - this is your domain and results in your domain being set to use your nameservers - this is an NS record, and there will be one for each nameserver that knows that domain.

>

> (c) An idea of how to configure secondary nameservers

Create a secondary zone, pointed to yourdomain.tld. - note the last dot.  Then you need to make sure you secondary server has a glue record in your TLD and an A record in your domain, add an NS record to YOUR copy of the domain pointing to the nameserver, and finally have it added as an additional NS record to the TLD's servers.

>

> (d) An overview of how MX records work

An MX record is a mail exchanger record, when you send mail to a host the following happens:

- An attempt to resolve it as an A record occurs.

- An attempt to resolve it as an MX record occurs.

   - Each returned MX record points to an A record that is resolved.

      - Mail delivery is attempted at the A records in order of weighting.

The MX records take priority, to allow an A record to exist for a host, but that host not to receive mail.

MX records have a weighting, the lowest takes mail first, then if that is down the next highest, and so on.  MX records with the same weighting are attempted randomly.

If all MX records bounce, the message is queued but eventually bounces with a failure.  If there are no MX records, and no A record, the mail bounces instantly.  If there is an A record, delivery is attempted and on failure, it bounces instantly.

>

> (d) An overview of Reverse DNS records (and whether I need these)

>

You do need these to deliver mail, you also need these if you wish to run a netblock, since it can be revoked by the issuer if you fail to do so.

As the owner for a netblock, you also have rights to a second domain - in in-addr.arpa.

This domain follows the reverse of an IP, so it can be followed down through the ownership chain, for example if RIPE issued you the address space 192.168.0.0/24 you would have the zone:

0.168.192.in-addr.arpa.

You could set up www here, but it wouldn't be much use.  More use would be to set up a PTR record for your SMTP server, which is at 192.168.0.8:

8.0.168.192 PTR mymail.mydomain.tld.

Note that when working with DNS you really do need the final dot, otherwise it'll exist in your current domain.  This is the common cause of lots of problems like cname's not resolving correctly and instead trying to go to mymail.mydomain.tld.mydomain.tld.

A cname is an alias.

------

Records you need to know about are:

SOA - the actual domain as it is stored on your system.

A - a hostname to IP

PTR - an ip to hostname

SVR - a common service (e.g. - ldap and Kerberos to log in to active directory in a domain)

MX - mail exchanger

CNAME - an alias, or common name

TEXT - information or other details

You can explore from the client side and test everything is working by using nslookup.

To use nslookup, open a command prompt, define what record type you want, and type the name of the record.

For example:

C:\>nslookup

Default Server:  vex.nullify.net

Address:  192.168.0.5

> set type=a

> xerxes

Server:  vex.nullify.net

Address:  192.168.0.5

Name:    xerxes.nullify.net

Address:  66.98.178.74

> set type=ns

> nullify.net.

Server:  vex.nullify.net

Address:  192.168.0.5

nullify.net     nameserver = ns1.twisted4life.com

nullify.net     nameserver = queeg.nullify.net

nullify.net     nameserver = xerxes.nullify.net

queeg.nullify.net       internet address = 66.45.233.165

xerxes.nullify.net      internet address = 66.98.178.74

xerxes.nullify.net      AAAA IPv6 address = 2002:4262:b24a::4262:b24a

> set type=mx

> nullify.net

Server:  vex.nullify.net

Address:  192.168.0.5

nullify.net     MX preference = 20, mail exchanger = xerxes.nullify.net

nullify.net     MX preference = 30, mail exchanger = queeg.nullify.net

nullify.net     MX preference = 10, mail exchanger = firewall.nullify.net

nullify.net     nameserver = ns1.twisted4life.com

nullify.net     nameserver = queeg.nullify.net

nullify.net     nameserver = xerxes.nullify.net

firewall.nullify.net    internet address = 81.109.199.173

xerxes.nullify.net      internet address = 66.98.178.74

xerxes.nullify.net      AAAA IPv6 address = 2002:4262:b24a::4262:b24a

queeg.nullify.net       internet address = 66.45.233.165

Feel free to use my domain to explore it if you want, it (should be) set up correctly, and everything is public info anyway.  http://www.demon.net/toolkit/internettools/ contains some useful tools to test your domain from outside your own network if you don't have access to an external machine.

Exploring from the client side gives a good idea what the server side setup will need to be.

Permalink  2 Comments 

I don't normally talk about things like the Tsunami, or September 11. I let others who are much better qualified or more descriptive cover them and try not to clutter the net with more useless content, however with the deathtoll officially passing 125,000 confirmed dead - I have just one thing to say:

125,000 people are dead. Please donate something to help.

Permalink 

I've had IPv6 in testing on xerxes.nullify.net (in Texas, US) for some time as xerxes.ipv6.nullify.net but have now finally enabled it on the main hostname since it has been stable and worked reliably. I've also got it working from home (Surrey, UK) and am working on queeg.nullify.net (now New Jersey, US).

If anyone has any problems viewing anything please let me know.

Permalink 

Merry christmas and a happy new year everyone! Permalink 

This is possibly the best post I've seen on debugging .NET memory leaks (when the garbage collector isn't quite working as intended, or your program is keeping something alive longer than it should). Permalink 

You can do this using the OPENROWSET function in MS SQL Server, so:

SELECT * FROM OPENROWSET('MSDASQL', 'ConnectionString', 'SELECT * FROM mytable')

Which is great in a view for data consolidation - but even better is to remove the need for a connection string by connecting just once!

You can do this using sp_addlinkedserver and sp_addlinkedsrvlogin.  Requirements will change depending on what you want to connect to - if you need help with a particular one feel free to e-mail me.

You can then simply use the new 'server' you just set up as so:

SELECT * FROM OPENQUERY(servername, 'SELECT * FROM mytable')

Permalink 

Have you ever wondered how to check if a number is an integer in C#?  Wondered why Convert.ToInt32() surrounded by a try catch is so slow?  Well, this article is for you then.

As everyone should know, catching an exception is an extremely time consuming task, but there's no obvious way to check if a string is actually an integer.  And before the visual basic people all say about Microsoft.VisualBasic.Information.IsNumeric this is actually simply a try...catch around a Convert.ToInt32 call.

Okay, so what is the performance drop incurred by using a try...catch and why should you worry?

Well, it's slow - 1000 iterations of try...catch around a Convert.ToInt32() comes to 2515.625 ms.  Programmatically that's a HORRID use of CPU time.

Some people (particularly on blogs.msdn.com's comments) have suggested that this is simply something you must incur, however due to NumberStyles (in System.Globalization) containing an entry for Integer it needn't be. We can use Double.TryParse without the risk that the double we'll be getting back will contain anything but a valid integer.

This is amazingly faster - 100,000 (100 times more than with a try...catch!) worst case scenarios come to a grand total of 46.875 ms of cpu time used up.  A much better overhead.

It returns True if the string was an integer and false if not - altering the value of the double passed into it as an out parameter to be the correct amount if it succeeds.  Note that the if statements are just there to confuse the compiler so it doesn't optimise out the whole contents of each for loop.

Here's an example application (sorry, no walkthrough as I have too little time, but this should be simple enough!):

using System;

using System.Globalization;

namespace BlogExamples.IntegerValidation

{

   class IntegerValidator

   {

      static void Main(string[] args)

      {

      Console.WriteLine("Comparison of speed of try..catch checking of integers");

      Console.WriteLine("1000 iterations of try...catch Convert.ToInt32()");

      DateTime before = DateTime.Now;

      for (int i=0; i<1000; i++)

      {

         try

         {

            int t = Convert.ToInt32("testing");

            if (t>1000)

            {

               Console.WriteLine("Optimisation cheating");

            }

         }

         catch

         {

         }

      }

      TimeSpan duration = DateTime.Now - before;

      Console.WriteLine(duration.TotalMilliseconds+" ms total");

      CultureInfo MyCultureInfo = new CultureInfo("en-GB");

      Console.WriteLine("100000 iterations of Double.TryParse() (to be fair!)");

      DateTime before2 = DateTime.Now;

      for (int i=0; i<100000; i++)

      {

            double d = 0;

            Double.TryParse("testing", System.Globalization.NumberStyles.Integer, MyCultureInfo, out d);

            if (d>1000)

            {

            Console.WriteLine("Optimisation cheating");

            }

         }

         TimeSpan duration2 = DateTime.Now - before2;

         Console.WriteLine(duration2.TotalMilliseconds+" ms total");

         Console.ReadLine();

      }

   }

}

 

Which when run on my machine reports the following:

Comparison of speed of try..catch checking of integers
1000 iterations of try...catch Convert.ToInt32()
2515.625 ms total
100000 iterations of Double.TryParse() (to be fair!)
46.875 ms total

Permalink  1 Comments 

Yes, I know I haven't posted anything in over a month - I don't really have anything useful or relevant to post now either.

This is the unfortunate result of actually doing work rather than blogging, which has come about due to full time employment once again!

I'll possibly post something later on to do with C# and finding out if a string is an integer without using try...catch (it's not as simple as it sounds, no, that VB isnumeric thingy uses a try...catch!).

Permalink 

Then maybe you have something in your most recently used list that's needing a network lookup.  UNC pathnames were causing the problem for me.

You can clear your MRU lists by exiting visual studio, then opening registry editor and deleting the contents of the keys FileMRUList and ProjectMRUList in HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\

Permalink 

If your web service (or one you're consuming) is playing up (405 Gateway timeouts, other odd behaviour) when being debugged, maybe it's the VsDebuggerCausalityData header - it's a huge string seemingly mostly filled with AAAA!

You can disable this from being sent by adding the following in your App.Config file:

<configuration>
  <system.diagnostics>
    <switches>
      <add name="Remote.Disable" value="1">
    </switches>
  </system.diagnostics>
</configuration>

This will disable the debugger from getting involved with the badly configured server (the VS header is within the HTTP specs upper limit on size).

This has been annoying me for at least the past day trying to talk to a partner of works web service!

Permalink 

So for my 21st birthday I figured I'd treat myself to a new computer (which is missing a graphics card for the moment, so I have to use it over terminal services :-/) - it's spectacular...

Whilst most machines get ~1.7GB/s bandwidth to the system memory, and the latest Intel Xeo's get 2.6GB/s - with a NUMA enabled copy of Windows XP (ie - it has service pack 2) I get a nice 10GB/s.  And no, I'm not mixing up Gb and GB!  I think this is the fastest result for the SiSoft Sandra benchmark I've seen out there without overclocking...  Actually, even with overclocking I think it's the fastest!

I think that's the fastest ever memory benchmark result in sisoft sandra!

If you ever want performance, dual Opteron (AMD64 server CPU's) are definetely it when mixed with a good motherboard like the DK8N from Iwill!  I only had some minor problems with the Western Digital hard disks and trying to use both raid controllers at once.

(Thanks has to go out to http://www.rainbow-it.co.uk/ who managed to source all the components and have provided simply the BEST customer service - even when I wanted particularly special components - they beat Dabs in shipping time by months...)

Permalink 

Whilst I wait for someone to get back to me about something, I figured I'd quickly post about something that initially confused me about server controls on ASP.NET so that there's at least SOME new content!

ASP.NET server controls are simple components that run on the server and allow you to refactor a quantity of your sites code (such as a menubar) into a seperate module that is both reusable like a user control, and dynamic.  A server control can run code and also allows you to drag and drop it onto your pages.  A server control also has the ability to render itself at design time, so no more silly grey boxes - but rather a WYSIWYG situation (once it's built)!

So, once you've created a server control using VS.NET 2003 (or your choice of IDE!) you can easily add to the render override with something simple:

output.Write("<div class=\"mycssclass\">Hi there!</div>");

Any HTML will work, and all is fine if you just want to insert static HTML.

But what if you want to use the server control as if it were an ASP.NET application - or winforms control?

You know, so you can click a link or a button and it'll do 'something' and remember that state.

To do this you will need an event handler attached to a control.  So you create an instance of a control and delegate its event to the handler!  In winforms this is extremely easy, but in ASP.NET making it work right requires you set it all up early enough in your code!  This is the gotcha that had me stuck for a couple of hours when I first learnt it.  I did it in the render override.

Instead, change your render override to read as follows:

protected override void Render(HtmlTextWriter output)
{
   output.Write("<div class=\"myCSSClass\">");
   this
.RenderContents(output);
   output.Write("</div>");
}

This will allow you to render the controls at the right time and yet create them early enough - which will let ASP.NET create the eventhandler and wire it up for you.

Now, to create the controls that will be rendered you need to create a new override:

public LinkButton l;

protected override void OnInit(EventArgs e)
{
   base
.OnInit (e);
   l = new
LinkButton();
   l.Text = "Click me!  I'm a link that triggers an event on the server!";
   l.Enabled = true
;
   EventArgs args = new
EventArgs();
   l.Click += new
EventHandler(this.l_Click);
   this
.Controls.Add(l);
   Literal br = new
Literal();
   br.Text = "<br />";
   this
.Controls.Add(br);
}

This will create two controls - which will be rendered in the render method.  You can now create the event handler and any code you place in it will work!  If you had created the controls in the render method itself you would have found that although they posted back to the server, they didn't call the event handler.

(Note: += means "add one of" and "base" is the WebControl you are inheriting from when creating a server control.)

A quick example event handler for those who've never done one before:

void l_Click(object sender, EventArgs e)
{
   l.Text = "Thanks!";
}

Permalink 

If wbms's security is in doubt, how about using a web based msn from the horses mouth?

http://webmessenger.msn.com/

Microsoft's own web based msn messenger should be more reliable.

(Excuse for lack of posting: Tackling an interop issue)

Permalink 

I've been asked by some friends to upload some photos of Ballard - a building at Collingwood College where I used to work (yes, the evil workplace I have thankfully left was a College!).

They are really poor quality as they are just what I managed to take using my camera phone, and were (all but one) already photos of the building from the past.

If anyone reading this wants to contribute some other photos feel free to e-mail me with them and I'll upload them.  I also have a small forum for discussion by Collingwood College alumni - incedentally they have pictures of the new building that will be replacing it at the official site.

Permalink 

You can now finally order a copy of Beta 1 of Visual Studio 2005 in Europe - it's only £3 and is available from here. Permalink 

Sorry for the lack of entries, I've been pre-occupied with non-programming work things.  I will be building an intranet shortly though (whether the person that mentioned it actually wants it or not since it'll keep my technical skills active - will probably actually build 'bits' similar to sharepoint if I don't choose to go that route), so should have something interesting to post in the next few weeks.

The big question is, sharepoint or code?

Permalink 

This is just google juice as an experiment - hopefully after google gets this searching for a cryptic number will lead here. Permalink 

Dina (no url/blog yet!) mentioned wbMSN to me.  I'm not sure of the security of your password if you use it, however the concept is great - it allows you to use MSN without actually being logged into the smart client so you can chat if MSN Messenger itself is blocked on your corporate network (although then it's still inadvisable ;)).

Permalink 

So, I manage to bump into an article by Sam Gentile who is complaining about SQL Express.

He complains there's no manual, docs, sample database or user interface.

I do believe there's a lack of documentation - it could do with coverage of the new features, however MSDE had no user interface, sample database or documentation.  It's a royalty free, application deployable database - not SQL Server 2005 Enterprise Edition.

The product is a good year away at least!  And given what has already been written in various weblog entries and comments you can get the key parts to work fine.  Creating/importing a sample database is also simple enough as to be a good entry level test of the user to see if they actually should be playing with the product.

Beta means Beta, not "finished product to try out" - if will always take some effort to get the most out of a beta.

Permalink 

As of 30 June 2004 Office 2000 is no longer supported - well, there's always Microsoft extended support, but that's it - no more bugfixes or patches to be released - and even extended support only lasts till June 30 2009, when even the download site will vanish.

I'm using Office 2003 here, and very happy - particularly with Outlook and OneNote, however almost every tool has improved considerably since the 2000 version.  Hopefully the next version of Office will include support for languages other than VBA so people who program in languages like C# or C++ won't have to suffer VB!

But the 2000 version was the first version that was actually reliable and didn't crash all the time on people.  And for that there should be a nod of the head.  My memories of 97 are that of a downright bad product (although it wasn't lacking features).

Permalink 

The new version of MS SQL Server has a cut down version, like SQL Server 2000 had (MSDE) called SQL Server Express.

The restrictions on the new version are much more sensible for deployments, as rather than being limited to a predefined amount of work they're limited to storage space and hopefully clients are not likely to set up >4GB datasets of work data without being able to afford to buy a full copy of SQL Server.

The big plus though, is that you can have a .NET assembly work INSIDE your database as if it were a stored procedure, this offers major advantages - ie - a trigger can now send an MSN message or post to a web service.  And that's not touching the performance differences of code in .NET.

This is further differentiating MySQL and MS SQL, which is how I like things to be since both are excellent databases.

MySQL is the definitive victor in the price/ease of use arena for data warehousing and small applications whilst MS SQL server will be the victor in the performance/features arena for smart applications or where the data will be accessed from different systems (where stored procedures/.NET assemblies enable code reuse and advanced server side logic).

Permalink 

This one had me and google stumped for a few minutes yesterday till I remembered that dBASE isn't actually a relational database but is a flat file one.

Each file is one table, so use the file management classes in .NET to list the tables your connection string has opened!

Unfortunately there's also no way to list tables in ODBC that I can see in .NET for the moment, so if you want to use a different database format you would be better off using OLE or ADO to connect if you can.

Update: Whoops, here's the code I forgot to put in:

private OdbcConnection connection;

private string dbpath;

public dBaseEasyDBConn(string path)

{

dbpath = path;

Console.Write("Opening dBASE Files...");

connection = new OdbcConnection("Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq="+path);

connection.Open();

Console.WriteLine("Done");

}

public string[] GetTables()

{

int position = 0;

string[] templist = Directory.GetFiles(dbpath, "*.dbf");

string[] filelist = new string[templist.GetLength(0)];

foreach (string s in templist)

{

filelist[position] = s.Replace(dbpath, "").Replace(".DBF", "").Replace("\\", "");

position++;

}

return filelist;

}

Permalink  1 Comments 

I'm currently sitting here considering what 'acceptable performance' is in a variety of situations, ranging from databases to user interfaces, or back end control systems.

The answer in most cases is:

It changes depending on your situation.

Even what is acceptable in a real-time environment varies dramatically, for example software designed to change the course of a cruise missile would need to respond quick enough to keep up with the rate of change of terrain, whereas something monitoring the change of temperature in a green house would likely not need to process the data faster than once every ten seconds.

A database must be atomic, as soon as you commit a transaction the data MUST exist in the database, but with concurrent connections and multiple physical CPU's this is clearly impossible without the database working sequentially - so acceptable performance in this case is "fast enough that nobody notices, but not fast enough to slow down total performance".

However, there is one exception to it being variable depending on the task:  When the user is involved.

What is acceptable performance for a user interface?

Back in the days pre-DOS and PC era people likely waited the same amount of time for applications as they do today only with fewer features.  (Obviously there were some exceptions, I remember waiting 5 minutes for a word processor to load, but things evened out pretty quickly since nobody WANTED to wait that long).

Firstly, there are two things to monitor to decide on performance.  How fast the application is available to be told what to do and how much you can tell it to do without actually needing to wait.  There are simple answers to both.

The second one is commonly ignored by a lot of bespoke software developers, and really big players who shall remain nameless - in the education sector the key piece of software in UK schools had serious problems with concurrency, and even after a full rewrite still has problems with concurrency of use of a single application - you tell it what to do and go have a cup of tea/coffee - it might be done when you get back.

This is obviously unacceptable, and companies like Microsoft who can afford to do user studies have clearly looked at the problem - for example, how long do you wait whilst you're saving in Word?  How about printing?

Correct - you don't, even if it takes a while a seperate thread is doing the actual work so there is zero delay in the user interface - you can even be typing away as it saves or prints.  They don't do it everywhere, but they do do it whereever the user would have to wait a varying amount depending on the data being altered.

This ensures that Word acts speedy even with a hundred megabyte document.

The question is, would anyone be willing to wait at that point to save the development work?

Whilst the answer is 'probably not' there would be a point where people wouldn't mind word freezing - would you mind a 1/2 a second on a save?  How about 2 seconds?

This brings me onto the issue of actual delay before the application is usable again.  What is acceptable here?

The first delay is loading the application.  This is dependant on what the user wants to do, since we don't know in advance what they want to do our user interface must APPEAR to load almost instantly so that we can shave an additional second or so of time off our REAL loading time whilst the user decides what to click or press.

The second delay is the activity of doing something with the application, and can consist of one of two things from a user perspective:

  • Critical continuity activities
  • Non-critical activities (note - non-critical to UI flow, not anything else)

In the case of critical activies that the UI is dependant on, obviously the user must wait - unfortunate as it is, they will appreciate that it must happen.  They might not be happy, but it IS going to take time to load the document they want to look at (even if just the first page is loaded for display purposes before the rest of the data is loaded).  In these cases you can try as hard as possible, but you will always cause the user to wait - sometimes a nasty amount of time.

The non-critical activies are ones that do not have to occur to leave the user interface operable.  Saving is a good example, so is printing and seach and replace - although this one is commonly not implemented properly.  These activities should be implemented as seperate threads, with the user able to continue with their task, or do an additional slow task at the same time to avoid any actual period where the user is twiddling their thumbs.

So, in essence the only real answer to both key areas of UI performance is THE USER WANTS IT NOW unless it HAS to take longer, and then they should be allowed to do something else at the same time!

I wish developers would take the perspective of the actual end user when writing the application.  We would see a lot more multi-threaded, multiple document interface applications I'm sure.

Congratulations to Microsoft for getting it right.

Permalink 

A good friend of mine and his father are doing the London Bikeathon - a 26 mile ride for Leukaemia Research.

If anyone would like to sponsor them, even a tiny token amount please donate/pledge something.

Permalink 

It seems as though Microsoft have a little competition going - and it revolves around the Visual Studio 2005 Express line of products.  Note that this includes the new version of SQL Server!!

If you're like me and have been eager to get your hands on a copy of Visual Studio 2005 - this is a good way to check out some of the new features - even if most are missing from these small applications.

This is exactly the right idea and will hopefully encourage more people to use .NET!

Update: Who cares about the little bits (although they're available and you can actually download them, unlike whidbey for the moment).  The almighty whidbey is ALSO in beta!

Permalink 

Matt Warren over at The Wayward WebLog is seemingly in a war of... posting with those who are only posting work related stuff.

As a sign of support I'm posting a link to his blog, not that my meagre quantity of visitors will make much of a difference but you can always hope ;)

That and I'm not going to spam for his blog, it's not THAT good.  Well, not yet.

So please, visit his totally irrelevant blog and read some of the good stories, gibberish, filler he's written.

Permalink 

This is a nice neat way of resizing an image, I've simplified it and de-refactored (?) it for simplicity.

Firstly, you ask for your image from the database:

SqlCommand cmd = new SqlCommand("SELECT image FROM images WHERE id=@id", connection);
cmd.Parameters.Add("@id", Request.QueryString["id"]);
SqlDataReader dr = cmd.ExecuteReader();

Allocate an array of bytes to store it in temporarily:

byte[] image = null;
while
(dr.Read())
{
   image = (byte
[])dr.GetValue(0);
}
dr.Close();

Now you have an array of bytes that contains your image, you can freely load it into a bitmap from the array:

Bitmap b = (Bitmap)Bitmap.FromStream(new MemoryStream(image));

And you can resize that bitmap easily using the overloaded bitmap constructor:

Bitmap output = new Bitmap(b, new Size(320, 240);

One resized bitmap that you can now save or send anywhere - including Response.OutputStream!

Permalink 

I've added CDATA's to my rss feed to prevent the html from FreeTextBox 2.0 escaping and making my feed invalid.

I've also added photo album support to SiteBuilder, although I'm not sure what I'm going to do with it until I add security rights.

Update: I put a few of my better photos in it as a test.

Permalink 

What has happened to me??  This used to be a staunchly anti Microsoft blog.  Well, when it was tech oriented.

I think the stuff over at http://blogs.msdn.com is infectious, I've posted more programming and techie articles since reading that site.  And it's all been favouring Microsoft...

Hum...

Uh oh, I might've been evangelised without realising it by Robert Scoble!!

Permalink 

I just found an article at http://blogs.msdn.com/mszCool/archive/2004/06/14/155420.aspx that goes really well with my old article about using reflection to build plugins.

Basically the article covers how to change the permissions of the appdomain to allow only permitted actions - a great thing to do if you want your users to be able to build the plugins!

(Update five years later in 2009: Also I forgot all about this article and did my own example here http://www.nullify.net/ViewArticle.aspx?article=315 )

Permalink 

All my code related articles, answers to questions, random bits and pieces that are of use are all listed here if you wish to ever revue them.  I'll add an entry to the menu as soon as I get a chance. Permalink