Standing on the shoulders of giants. RSS 2.0
# Wednesday, August 16, 2006

Although there are several ways in ASP.Net to influence the way DateTimes are displayed some methods are better than others and some are evil.

The easiest way to display DateTime and have some influence on them, is to specify the culture and the uiCulture in the globalization tag in the web.config. This is the preferred way if you can use the default date/time formats in that culture.

Example:

<%=DateTime.Now %> is rendered as "16-8-2006 10:14:49" with this globalization tag and rendered as "8/16/2006 10:18:37" with the culture and uiCulture set to en-US.

If you want a little more control, or when the default date/time formats don't offer enough flexibility you can specify a format in the ToString method of the DateTime object. This will still use the culture specified in the web.config for the (abbreviated) names of the months. The downside to this method is that you have to remember to set the correct format string, every time you want to display a date/time.

Example:

<%=DateTime.Now.ToString( "dd MMM \\'yy" )%> is rendered as "16 août '06" with the culture set to fr-FR ( the \\ are required for escaping the ' ).  

 When you want to offer your users a localized version of your web-application, you can't rely on the globalization settings in the web.config, instead you'll have to either set the Culture and UICulture of the current executing thread or use one of the ToString overrides that accepts an IFormatProvider. When you only specify an IFormatProvider, the default (or G) format is used to render the string and although you can override the default format, that is generally considered evil.

Example:

<%=DateTime.Now.ToString( new System.Globalization.CultureInfo("es-ES")) %> is rendered as "16/08/2006 11:43:11", while <%=DateTime.Now.ToString("dd MMM \\'yy", new System.Globalization.CultureInfo("es-ES")) %> is rendered as "16 ago '06".

These methods were the only methods that were available on version 1.x of the .Net framework. In .Net 2.0 you have the ability to define a custom culture using the CultureAndRegionInfoBuilder class. After creating a new culture, this new culture can be installed on a computer and used by any application on that computer. This allows all (web-)applications on that computer to use the same formatting for dates, and numbers, casing etc. This way you can change the default format for string rendering in a less evil way.

Example:

First setup the custom culture using a console application, since this requires administrator rights.

class Program{ 

static void Main( string[] args ) {

if (args.Length == 0 || args[0].EndsWith("i", StringComparison.OrdinalIgnoreCase)) {

RegisterNewRegion();
Console.WriteLine("Registered new region \"x-en-US-custom\".");
} else if (args[0].EndsWith("u", StringComparison.OrdinalIgnoreCase)) {
UnRegisterNewRegion();
Console.WriteLine("Unregistered new region \"x-en-US-custom\".");
} else {
Console.WriteLine("use /i to register and /u for unregister.");
}

Console.WriteLine("Press enter.");
Console.ReadLine();
}

static void RegisterNewRegion() {

// instantiate a new CultureAndRegionInfoBuilder object named x-en-US-demo
CultureAndRegionInfoBuilder cib = new CultureAndRegionInfoBuilder("x-en-US-custom", CultureAndRegionModifiers.None);
//load the culture data from the default en-US culture and region
cib.LoadDataFromCultureInfo(new CultureInfo("en-US"));
cib.LoadDataFromRegionInfo(new RegionInfo("US"));
// set the custom date/time format
cib.GregorianDateTimeFormat.ShortDatePattern = "dd-MM-yy";
cib.GregorianDateTimeFormat.LongDatePattern = "dd MMM \\'yy";
cib.GregorianDateTimeFormat.ShortTimePattern = "HH:mm";
cib.GregorianDateTimeFormat.LongTimePattern = "HH:mm";

// register the culture
cib.Register();
}

static void UnRegisterNewRegion() {

CultureAndRegionInfoBuilder.Unregister("x-en-US-custom");
}

}

Now you can use your custom culture in any web-application, like the previous examples.

<%=DateTime.Now %> is rendered as "16-8-2006 10:14:49" with this globalization tag

Another use would be for writing dates to a log-file, when you need to sort or parse them in future.

Thanks to michkap from Sorting It All Out for the tip on CultureAndRegionInfoBuilder and the post that inspired this post.

Wednesday, August 16, 2006 4:59:42 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
ASP.NET
# Sunday, August 13, 2006

 Microsoft released a beta of Live writer [0] this weekend and says it works with dasBlog, so this is a test to see if it actually does.

[0] Writer zone

 

Live writer screenshot

Sunday, August 13, 2006 10:56:31 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
General
# Wednesday, August 02, 2006

They have been around for a bit, hiding as delegates, but they're getting some much deserved attention from Joel [0] and Raymond [1].

Joel is critical about the implementation in C#; while Raymond Chen is starting a series about their implementation and subtle errors. I'm not sure I can totally agree with Joel, since I like the obviousness (and typesafe-ness) of defining delegates and calling them as methods, while the compiler handles the plumbing.

links:
[0] Can your programming language do this?
[1] The implementation of anonymous methods in C# and its consequences (part 1)

[update 2006-08-05]

Ramond added 2 new entries to his anonymous methods series:

The implementation of anonymous methods in C# and its consequences (part 2)
The implementation of anonymous methods in C# and its consequences (part 3)

Wednesday, August 02, 2006 1:59:09 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
C#
# 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)
Thursday, January 12, 2006 4:42:19 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0] - Trackback
Codesnippet | Development
# Wednesday, January 04, 2006

See also: A horrible way to calculate a squareroot

using System;
using System.Query;

namespace SquareRoot
{
class Program
{
static void Main(string[] args)
{
int input = 16;
decimal margin = 0.01M;

Func<decimal, decimal> abs = (decimal x) =>
x < 0 ? -x : x;

Func<decimal, bool> goodEnough = (decimal guess) =>
abs(guess * guess - input) < margin;

Func<decimal, decimal> newGuess = (decimal guess) =>
(guess + input / guess) / 2;

Console.WriteLine( "Guess {0}", Try(1, goodEnough, newGuess) );
Console.ReadLine();
}

static decimal Try(decimal guess, Func<decimal, bool> goodEnough, Func<decimal, decimal> newGuess)
{
if (!goodEnough(guess))
{
return Try(newGuess(guess), goodEnough, newGuess);
}

return guess;
}
}
}

Wednesday, January 04, 2006 5:32:56 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0] - Trackback
Development
# Monday, January 02, 2006

But fun to write:

using System;

class MyClass {
public static void Main() {

int input = 16;
decimal margin = 0.01M;

Func<decimal, decimal> abs = delegate(decimal x) {
return x < 0 ? -x : x;
};

Func<decimal, bool> goodEnough = delegate(decimal guess) {

return abs(guess * guess - input) < margin;
};

Func<decimal, decimal> newGuess = delegate(decimal guess) {
return (guess + input / guess) / 2;
};

Console.WriteLine("guess {0}", Try(1, goodEnough, newGuess) );
Console.ReadLine();
}

static decimal Try(decimal guess, Func<decimal, bool> goodEnough, Func<decimal, decimal> newGuess) {

if (!goodEnough(guess)) {
return Try(newGuess(guess), goodEnough, newGuess);
}

return guess;
}


delegate ReturnType Func<U, ReturnType>(U guess);
}

Inspired by Joel and Chris.

Monday, January 02, 2006 5:37:31 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0] - Trackback
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

Thursday, December 08, 2005 6:33:01 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0] - Trackback
Codesnippet
# Wednesday, December 07, 2005

The lowest level useful description of the goal of any software is probably best put as "elicit a positive emotional response
in a human".

2005 – DJ Mort

Wednesday, December 07, 2005 8:13:51 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0] - Trackback
Development

<?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)

Wednesday, December 07, 2005 5:27:25 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0] - Trackback
Codesnippet | Visual Studio 2005
Ads
About
© Copyright 2014
Paul van Brenk
Sign In
newtelligence dasBlog 2.3.12105.0
All Content © 2014, Paul van Brenk
DasBlog theme 'Business' created by Christoph De Baene (delarou)