Standing on the shoulders of giants.
 Sunday, March 04, 2007

Although generally a bad idea [0], there is another problem. The System.Web.Caching.Cache doesn't call dispose on the items removed from the cache, causing a resource leak. To prevent this resource leak, add a CacheItemRemovedCallback in which you dispose of the object.

 

// add the item to the cache, note the callback

HttpRuntime.Cache.Add("myKey", myClass, null, DateTime.Now.AddSeconds(5), 
     Cache.NoSlidingExpiration, CacheItemPriority.Default, 
     new CacheItemRemovedCallback( OnRemoved ) );

// callback function

void OnRemoved( string key, object value, CacheItemRemovedReason reason ) {

     IDisposable disposable = value as IDisposable;
     if (disposable != null) {
          disposable.Dispose();
     }
}

 

[0] Should you really be caching an object containing unmanaged resources, which usually are scarce?

04 Mar 2007 17:58 W. Europe Standard Time  #    Comments [0] - Trackback
Codesnippet | C#

 Friday, January 05, 2007

public class A {
    public virtual void AA(){}
}

public abstract class B : A{
    public abstract override void AA();
}


If you now would define a class C : B, then C must implement the method AA again.
05 Jan 2007 11:23 W. Europe Standard Time  #    Comments [0] - Trackback
Codesnippet | C#

 Wednesday, September 20, 2006

The best new feature in iTunes 7 is the cover art browser, the not so good feature is the fact that it doesn't work so good on Windows Vista. So after moving back to Mediaplayer and missing the cover art, which takes forever to download for a decent sized library in iTunes. I put together this codesnippet, which lets downloads the cover art from the iTunes store for the specified artist/album.

The interesting part is the headers you have to send with your request:

request.Headers.Add("X-Apple-Tz", "7200");
request.Headers.Add("X-Apple-Store-Front", "143457");
request.Headers.Add("Accept-Language", "en-us, en;q=0.50");
request.Headers.Add("Accept-Encoding", "gzip, x-aes-cbc");
request.UserAgent = "iTunes/7.0 (Macintosh; U; PPC Mac OS X 10.4.7)";
request.AutomaticDecompression = DecompressionMethods.GZip;

Also note that the HttpWebRequest class automatically decompresses the response.

Program.cs (3.44 KB)Program.txt (3.44 KB)

Note: this code is based on the perl library by Jesper Nøhr and works as long as Apple doesn't change anything.


20 Sep 2006 15:38 W. Europe Daylight Time  #    Comments [2] - Trackback
Codesnippet | Fun

 Thursday, January 12, 2006

Well, maybe...

 

public class GenericComparer : IComparer {

public GenericComparer( CompareDelegate doCompare ){

if( doCompare == null ){

throw new ArgumentNullException("doCompare");

}

this.doCompare = doCompare;

}

public int Compare( object x, object y ){

if( x == null ){

if( y == null ){

return 0;

}

return -1;

}

if( y == null ){

return 1;

}

return doCompare(x,y);

}

private CompareDelegate doCompare;

}

public delegate int CompareDelegate( object x, object y );

Update:
My colleague Branimir did a little experimentation and found this implementation is similar in performance to a 'regular' methodcall when sorting around 10.000 items.

LastComparer.zip (30.65 KB)
12 Jan 2006 13:42 W. Europe Standard Time  #    Comments [0] - Trackback
Codesnippet | Development

 Thursday, December 08, 2005

Code to create a random validationKey and decryption for use in the machinekey element of the web.config.

Note: valid values for the decryptionKey length are 8 (for DES) or 24 (for 3DES), the resulting key is twice as long and for validationkey 20 to 64.

using System;

using System.Text;

using System.Security.Cryptography;

namespace Crypto {

public class KeyCreator {

public static void Main(String[] args) {

String[] commandLineArgs = System.Environment.GetCommandLineArgs();

string decryptionKey = CreateKey(System.Convert.ToInt32(commandLineArgs[1]));

string validationKey = CreateKey(System.Convert.ToInt32(commandLineArgs[2]));

Console.WriteLine("<machineKey validationKey=\"{0}\" decryptionKey=\"{1}\" validation=\"SHA1\"/>", validationKey, decryptionKey);

}

static String CreateKey(int numBytes) {

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

byte[] buff = new byte[numBytes];

rng.GetBytes(buff);

return BytesToHexString(buff);

}

static String BytesToHexString(byte[] bytes) {

StringBuilder hexString = new StringBuilder(64);

for (int counter = 0; counter < bytes.Length; counter++) {

hexString.Append(String.Format("{0:X2}", bytes[counter]));

}

return hexString.ToString();

}

}

}

source: mskb312906

08 Dec 2005 15:33 W. Europe Standard Time  #    Comments [0] - Trackback
Codesnippet

 Wednesday, December 07, 2005

<?xml version="1.0" encoding="utf-8" ?>

<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

<CodeSnippet Format="1.0.0">

<Header>

<Title>sourcesafe header</Title>

<Shortcut>header</Shortcut>

<Description>Code snippet for sourcesafe header.</Description>

<Author>Paul van Brenk</Author>

<SnippetTypes>

<SnippetType>Expansion</SnippetType>

</SnippetTypes>

</Header>

<Snippet>

<Declarations>

<Literal />

</Declarations>

<Code Language="csharp" Kind="file" Delimiter="*">

<![CDATA[#region SourceSafe header

// $Author: $

// $Modtime: $

// $Workfile: $

// $Revision: 1 $

#endregion

*end*]]>

</Code>

</Snippet>

</CodeSnippet>

</CodeSnippets>

File Attachment: sourcesafe_header.zip (550 bytes)

07 Dec 2005 14:27 W. Europe Standard Time  #    Comments [0] - Trackback
Codesnippet | Visual Studio 2005

 Sunday, November 27, 2005

Update: Still haven't found what is causing the exception, but I think the message of the exception is incorrect. For now I'm sticking with the Knuth Shuffle algorithm from the PowerCollections. As suggested by Cyrus.

int[] ints = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

System.Random rand = new System.Random((int)DateTime.Now.Ticks);

Array.Sort(ints, delegate(int x, int y){

// since you’re not allowed to return anything else than 0 for x.CompareTo(x)

if (x == y) {

return 0;

}

return rand.Next(-1,2);

}

);

note: This still throws an exception sometimes, claiming x.CompareTo(x) didn't return 0. I haven't found out why this happens or a pattern when this is happening, but I'll keep looking.

27 Nov 2005 13:10 W. Europe Standard Time  #    Comments [0] - Trackback
Codesnippet

 Thursday, October 13, 2005

public static string GeneratePassword(int length) {

string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@$?";

Random rnd = new Random( (int)DateTime.Now.Ticks );
            
char[] chars = new char[length];


for(int i = 0;i<length;i++) {
chars[i] = allowedChars[ rnd.Next( allowedChars.Length ) ];
}

return new string(chars);
}

When running in a tight loop, you're better of pulling the initialisation of the randomGenerator outside the method, or not use DateTime.Now.TickCount as the seed.

13 Oct 2005 15:12 W. Europe Daylight Time  #    Comments [0] - Trackback
Codesnippet

 Tuesday, August 23, 2005

The easiest way on sql server 2000 is to change the collation on the column you want to do the search on:

ALTER TABLE dbo.Customers ALTER COLUMN CustID char(8) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL

23 Aug 2005 18:32 W. Europe Daylight Time  #    Comments [1] - Trackback
Codesnippet | SQL

 Friday, August 12, 2005

System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

Note: this will be 0.0.0.0 if you use it in the code-forward of an aspx page.

12 Aug 2005 11:54 W. Europe Daylight Time  #    Comments [0] - Trackback
Asp.Net | Codesnippet

 Wednesday, July 27, 2005

public static string HashPasswordForStoringInConfigFile(
   string password,
   string passwordFormat
);

In the FormsAuthentication class in the System.Web.Security namespace.

The first parameter is the string you want hashed, the second is the hashalgorithm, “sha1” or “md5”, to use.

[more info on msdn]

27 Jul 2005 17:22 W. Europe Daylight Time  #    Comments [0] - Trackback
Codesnippet | Development

 Monday, July 18, 2005

This code shows how to deserialize a string containing xml to an object using a StringReader and an XmlTextReader (remember to insert a using-statement, where appropiate). The deserialized class also shows how to handle xml-arrays using the serialization attributes.

// ===============================================================================
// Copyright (C) 2005 Paul van Brenk
// All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
// FITNESS FOR A PARTICULAR PURPOSE.
// ==============================================================================
// Deserializing a string containing xml and an xml-array.
// ==============================================================================


using System;
using System.Collections;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class MyClass
{
    public static void Main()
    {
    
        string xml = "<person>" +
                        "<firstname>Paul</firstname>" +
                        "<lastname>van Brenk</lastname>" +
                        "<addresses>" +
                        "    <address>" +
                        "        <street>Home Street</street>" +
                        "        <number>80</number>" +
                        "        <postalcode>1000 AA</postalcode>" +
                        "        <city>Home Town</city>" +
                        "        <country>The Netherlands</country>" +
                        "    </address>" +
                        "    <address>" +
                        "         <street>Work Street</street>" +
                        "        <number>100</number>" +
                        "        <postalcode>1000 BB</postalcode>" +
                        "        <city>Work Town</city>" +
                        "        <country>The Netherlands</country>" +
                        "    </address>" +
                        "</addresses>" +
                    "</person>";
                    
        XmlSerializer ser = new XmlSerializer( typeof(Person) );
        
        StringReader reader = new StringReader(xml);
        XmlTextReader xmlReader = new XmlTextReader(reader);
        
        Person person = (Person)ser.Deserialize(xmlReader);
    }
}

[XmlRoot("person")]
public class Person{

    public Person(){
        // required for serializer
    }
    
    [XmlElement("firstname")]
    public string FirstName;
    [XmlElement("lastname")]
    public string LastName;
    
    //defines the arraynode
    [XmlArray("addresses")]
    // defines the node in the array
    [XmlArrayItem("address")]
    public Address[] Addresses{
        get{
            if(this.addresses == null ){
                return new Address[0];
            }
            return this.addresses;
        }
        set{
            this.addresses = value;
        }
    }

    [XmlAnyElement()]
    public XmlElement[] UnknownElements;

    private Address[] addresses;
}

// this attribute has no influence on the rendering
// of the element as part of an Xml-array.
[XmlRoot("address")]
public class Address{

    public Address(){
        // required for serializer
    }
    [XmlElement("street")]
    public string Street;
    [XmlElement("number")]
    public int Number;
    [XmlElement("postalcode")]
    public string PostalCode;
    [XmlElement("city")]
    public string City;
    [XmlElement("country")]
    public string Country;
}

18 Jul 2005 17:07 W. Europe Daylight Time  #    Comments [0] - Trackback
Codesnippet

 Friday, July 15, 2005

Returning an ArrayList is as bad or worse as returning an object from most methods, so don’t. When you return an ArrayList, anything could be in there, so I have to try and read your code, or hope your documentation is still correct, to find out what’s in there. A much nicer and more type-safe solution is to return an Array of the objects in your ArrayList, which is only 1 line of code more.

    public ArrayList BadNumbers{
        get{
            return this.items;
        }
    }
    
    public int[] GoodNumbers{
        get{
            if( numbers == null ){
                // it's not nice to return a null reference, when
                // an Array is expected.
                // That would mess up your foreach loop badly.
                return new int[0];
            }
            
            // conversion is done here instead of at the call site
            return (int[])numbers.ToArray(typeof(int));            
        }
    }
    
    private Arraylist numbers = new ArrayList();

15 Jul 2005 11:33 W. Europe Daylight Time  #    Comments [1] - Trackback
Codesnippet | Development

 Sunday, May 15, 2005

When serializing a class with an event, all classes subscribing to that event have to be serializable aswell. Usually you don't have any control over the classes subscribing to that event, or you don't want them to be remoted in the first place.

By adding the NonSerialized attribute to the event, with the field keyword, the field that holds the delegate for the event is stored is not serialized. So those subsribers no longer need to be serializable.

// ===============================================================================
// Copyright (C) 2005 Paul van Brenk
// All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
// FITNESS FOR A PARTICULAR PURPOSE.
// ==============================================================================
// Serializing a class with an event sample.
// ==============================================================================


using System;

namespace Paulb.CodeSnippets
{
    [Serializable]
    public class SerializableClass
    {
        public SerializableClass()
        {
            ///
        }
        
        // adding the NonSerialized attribute this way,
        // we don't serialize the field where the delegate for this event is stored,
        // that way those subscribers don't need to be serializable.
        [field: NonSerialized]
        public event EventHandler Event;
    }

    /// <summary>
    /// This class can not be serialized, since the serializable attribute is missing.
    /// </summary>
    public class NotSerializedClass{

        public NotSerializedClass(){
        
            serializable.Event +=new EventHandler(serializable_Event);
        }

        private SerializableClass serializable = new SerializableClass();

        private void serializable_Event(object sender, EventArgs e) {
            // handle event here
        }
    }
}

Some background on how events are compiled from "The C# programming language" p330:

"When compiling a field-like event, the compiler automatically creates storage to hold the delegate and created accessors for the event that add or remove event handlers to the delegate field."

This results in the pseudo code generated for the SerializableClass:

.class public auto ansi serializable beforefieldinit SerializableClass
extends object
{
.event [mscorlib]System.EventHandler Event
{

// event accessors

.addon instance void Paulb.CodeSnippets.SerializableClass::add_Event([mscorlib]System.EventHandler)
.removeon instance void Paulb.CodeSnippets.SerializableClass::add_Event([mscorlib]System.EventHandler)
}


.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
}

// delegate storage
.field private [mscorlib]System.EventHandler Event

}


disclaimer: Use at your own risk. This code is not threatsafe. Bugs, omissions let me know.

SerializingSample.cs (1.42 KB)
15 May 2005 16:19 W. Europe Daylight Time  #    Comments [0] - Trackback
Codesnippet | Development

I decided to add a new category, Codesnipper, to my blog, where I can post small classes, pieces of sample code and other usefull pieces of code. That way I'll be able to find it again and maybe it's usefull to someone else aswell. So without further ado: the Most Recently Used Hashtable.

Hashtable with a fixed capacity; removing the last one touched when inserting a new entry once the capacity has been reached. Returns null for items older then the maximum age.

// ===============================================================================
// Copyright (C) 2005 Paul van Brenk
// All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
// FITNESS FOR A PARTICULAR PURPOSE.
// ==============================================================================
// Hashtable with a fixed capacity; removing the last one touched when inserting a
// new entry once the capacity has been reached.
// Returns null for items older then the maximum age.
// ==============================================================================

using System;
using System.Collections;

namespace PaulB.Collections {

    /// <summary>
    /// CustomHashtable with a fixad capacity removing the oldest item first.
    /// </summary>
    public class MRUHashtable : IEnumerable {
    
        /// <summary>
        ///
        /// note: no max. caching time.
        /// </summary>
        /// <param name="capacity">number of items</param>
        public MRUHashtable( int capacity ) : this( capacity, TimeSpan.MaxValue ){
            //...    
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="capacity">number of items</param>
        /// <param name="maxAge">time to cache items in minutes (0 means no max. caching time)</param>
        public MRUHashtable( int capacity, int maxAge ) : this ( capacity, new TimeSpan(0, maxAge, 0) ){
            ///....
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="capacity">number of items</param>
        /// <param name="maxAge">time to cache items</param>
        public MRUHashtable( int capacity, TimeSpan maxAge ){
            this.itemTable = new Hashtable( capacity );
            this.timeTable = new Hashtable( capacity );
            this.capacity = capacity;
            this.maxAge = maxAge;
        }

        public void Add( object key, object value ){
            
            if( this.Count >= this.capacity ){
                this.RemoveOldestItem();        
            }

            this.timeTable.Add(key, DateTime.UtcNow);
            this.itemTable.Add(key, value);
        }

        public void Clear(){
            this.itemTable.Clear();
            this.timeTable.Clear();
        }

        private void RemoveOldestItem(){
            object item = null;
            DateTime lastAccess = DateTime.MinValue;
            foreach( object key in this.itemTable.Keys ){
                if( item != null && (DateTime)this.timeTable[key] > lastAccess ){
                    continue;
                }
                item = this.itemTable[key];
                lastAccess = (DateTime)this.timeTable[key];
            }
            this.Remove(item);
        }

        public IEnumerator GetEnumerator(){
            return itemTable.GetEnumerator();
        }

        public void Remove(object key){
            this.timeTable.Remove(key);
            this.itemTable.Remove(key);
        }

        public bool Contains( object key ){
            
            CheckAccessTime(key);
            this.UpdateAccessTime(key);
            return this.itemTable.Contains(key);
        }

        private void UpdateAccessTime(object key){
            if( this.timeTable[key] != null ){
                this.timeTable[key] = DateTime.UtcNow;
            }
        }

        private void CheckAccessTime(object key){
         //prevent stale information
            if( timeTable[key] == null || (DateTime.UtcNow - (DateTime)timeTable[key]) > maxAge ){
                this.Remove(key);
            }
        }

        public object this[object key]{
            get{
                CheckAccessTime(key);
                UpdateAccessTime(key);
                return this.itemTable[key];
            }
            set{
                if( this.itemTable[key] == null ){
                    this.timeTable.Add(key, value);
                }else{
                    this.UpdateAccessTime(key);
                }
                this.itemTable[key] = value;
            }
        }

        public int Count{
            get{
                return this.itemTable.Count;
            }
        }

        public object SyncRoot{
            get{
                return this.itemTable.SyncRoot;
            }
        }

        public ICollection Values{
            get{
                return this.itemTable.Values;
            }
        }

        private int capacity;
        private TimeSpan maxAge;
        private Hashtable itemTable;
        private Hashtable timeTable;
    }
}

disclaimer: Use at your own risk. This code is not threatsafe. Bugs, omissions let me know.

MRUHashtable.cs (3.85 KB)
15 May 2005 15:04 W. Europe Daylight Time  #    Comments [0] - Trackback
Codesnippet | Development