Monthly Archives: July 2007

Exploring formatting…

In the documentation you can read the following for CultureInfo:

The CultureInfo class holds culture-specific information, such as the associated language, sublanguage, country/region, calendar, and cultural conventions. This class also provides access to culture-specific instances of DateTimeFormatInfo, NumberFormatInfo, CompareInfo, and TextInfo. These objects contain the information required for culture-specific operations, such as casing, formatting dates and numbers, and comparing strings.

First i’ll initialize an instance of a customized CultureInfo and install it in the current thread:

CultureInfo appCultureInfo = new CultureInfo("en-US");
appCultureInfo.NumberFormat.NumberDecimalSeparator = ".";
appCultureInfo.NumberFormat.NumberGroupSeparator = " ";
appCultureInfo.NumberFormat.NumberDecimalDigits = 2;
appCultureInfo.NumberFormat.CurrencySymbol = "€";
Thread.CurrentThread.CurrentCulture = appCultureInfo;

Note: The culture in Thread.CurrentThread.CurrentUICulture is only used by the Resource Manager to lookup culture-specific resources at run-time. Since we’re not playing with resources, we don’t have to care about this one.

If you don’t provide the desired format specifier, you will get the generic format specifier “G” ( Standard Numeric, DateTime, Enumeration Format Strings) And now it’s time for a little demo:

public double SomeValue
{
 get { return 12345.6789; }
}

private void Form1_Load(object sender, EventArgs e)
{
 label1.Text = "default to generic format: " + SomeValue.ToString();
 label2.Text = "numeric format: " + SomeValue.ToString("N");
 label3.Text = String.Format("currency format: {0:C}", SomeValue);
 label4.DataBindings.Add("Text", this, "SomeValue", true, DataSourceUpdateMode.Never, string.Empty, "P");

 this.Column1.DefaultCellStyle.Format = "E1";
 this.Column1.DataPropertyName = "SomeValue";
 this.dataGridView1.AutoGenerateColumns = false;
 this.dataGridView1.DataSource = new Form1[] { this };
}



Another important interface for formatting is IFormattable which provides functionality to format the value of an object into a string representation. Put simply, it allows you to define your own format specifiers. Here is an example that allows the user to build his own representation of a Person:

class Person : IFormattable
{
 // omitted the code for 4 properties: Id, Name, Title and Birthday

 public override string ToString()
 {
  return ToString("{Id}, {Name}", null);
 }

 public string ToString(string format, IFormatProvider formatProvider)
 {
  string actualFormat = format;

  string[] replacements = new string[] { "Id", "Name", "Title", "Birthday" };
  for (int i = 0; i < replacements.Length; ++i)
  {
   actualFormat = actualFormat.Replace(replacements[i], i.ToString());
  }

  return string.Format(actualFormat, this.id, this.name, this.title, this.birthday);
 }
}

private void Form1_Load(object sender, EventArgs e)
{
 List<person> persons = new List<person>();
 persons.Add(new Person(1, new DateTime(1980, 4, 30), "Tim", "Sir"));
 persons.Add(new Person(2, new DateTime(1974, 4, 9), "Jenna", "Miss"));

 this.comboBox1.FormatString = "{Name} born on {Birthday}";
 this.comboBox1.FormattingEnabled = true;
 this.comboBox1.DataSource = persons;
}



Using interfaces with Drag and Drop

Earlier today i was refactoring some graphical components. I wanted to use an interface instead of concrete implementations for my drag and drop code… Although i was using an instance of Foo, and thus IFoo, the following code never allowed me to drop:

interface IFoo { }
class Foo : IFoo { }

private void label1_MouseDown(object sender, MouseEventArgs e)
{
 this.DoDragDrop(new Foo(), DragDropEffects.All);
}

private void Form1_DragEnter(object sender, DragEventArgs e)
{
 // for an instance of Foo it returns false,
 // if you use typeof(Foo) it returns true though...
 if (e.Data.GetDataPresent(typeof(IFoo)))
 {
  e.Effect = DragDropEffects.All;
 }
}

Simply wrapping the concrete instance in a DataObject results in the desired behaviour:

private void label1_MouseDown(object sender, MouseEventArgs e)
{
 this.DoDragDrop(new DataObject(typeof(IFoo).FullName,new Foo()), DragDropEffects.All);
}

Pondering about DateTime and it's Ticks…

Recently someone was able to convince me that there is no problem with using System.DateTime for the storage of localtimes (even if DST is in effect), because it works with Ticks and i bought into his base + offset story…. The following table explains his reasoning:

Utc Localtime Ticks (Localtime)
2007-10-27 23:59:59 2007-10-28 01:59:59 633291335990000000
+1 second 2007-10-28 02:00:00 633291336000000000
+2 seconds 2007-10-28 02:00:01 633291336010000000
+60 minutes 2007-10-28 02:59:59 633291371990000000
+60 minutes and 1 second 2007-10-28 02:00:00 633291332000000000
+60 minutes and 2 seconds 2007-10-28 02:00:01 633291332010000000

This reasoning gives you the impression that for each second 10000000 is added to the ticks.. However, this is faulty and in reality you get the following:

Utc Localtime Ticks (Localtime)
2007-10-27 23:59:59 2007-10-28 01:59:59 633291335990000000
+1 second 2007-10-28 02:00:00 633291336000000000
+2 seconds 2007-10-28 02:00:01 633291336010000000
+60 minutes 2007-10-28 02:59:59 633291371990000000
+60 minutes and 1 second 2007-10-28 02:00:00 633291336000000000
+60 minutes and 2 seconds 2007-10-28 02:00:01 633291336010000000

As you can see, instead of adding 10000000 to the ticks between 2007-10-27 00:59:59 and 01:00:00 in UTC there is a reduction of ticks in the localtime instead…. Because of this new DateTime(633291336000000000, DateTimeKind.Local) could represent both 2007-10-27 00:00:00 UTC and 2007-10-27 01:00:00 UTC… So if you want to keep out of trouble you’d better start storing your dates as UTC… If you don’t believe me, run the test yourself:

List<dateTime> localTimes = new List<dateTime>();

// start at 2007-10-27 23:59:59 UTC, which is 2007-28-10 01:59:59 localtime
DateTime utcBase = new DateTime(2007, 10, 27, 23, 59, 59, DateTimeKind.Utc);
localTimes.Add(utcBase.ToLocalTime());

// add 1 second to the base, which is 2007-28-10 02:00:00 localtime (first time)
localTimes.Add(utcBase.AddSeconds(1).ToLocalTime());

// add 2 seconds to the base, which is 2007-28-10 02:00:01 localtime (first time)
localTimes.Add(utcBase.AddSeconds(2).ToLocalTime());

// add 60 minutes to the base, which is 2007-28-10 02:59:59 localtime (first time)
localTimes.Add(utcBase.AddMinutes(60).ToLocalTime());

// add 60 minutes and 1 second to the base, which is 2007-28-10 02:00:00 localtime (second time)
localTimes.Add(utcBase.AddMinutes(60).AddSeconds(1).ToLocalTime());

// add 60 minutes and 2 second to the base, which is 2007-28-10 02:00:01 localtime (second time)
localTimes.Add(utcBase.AddMinutes(60).AddSeconds(2).ToLocalTime());

foreach (DateTime localTime in localTimes)
{
 Console.WriteLine(localTime.ToString("yyyy-MM-dd HH:mm:ss"));
 Console.WriteLine(localTime.Ticks);
 Console.WriteLine();
}

Update from localtime to UTC or any other timezone with Oracle

Imagine that you have a table with a column of the type DATETIME. You’ve been storing data as localtime and after a while you need to convert these datetimes to UTC. Here’s a possible approach:

UPDATE events SET start = SYS_EXTRACT_UTC(FROM_TZ(start, 'Europe/Brussels'));

You get a more generic variant using the AT TIME ZONE clause:

UPDATE events SET start = FROM_TZ(start, 'Europe/Brussels') AT TIME ZONE 'America/Denver';

About Authorization

Yesterday i visited an evening session about authentication and authorization at Compuware (Yes, i’ve got interesting collegues that are willing to share their knowledige). Anyway, i left the meeting with a couple of questions:

How does System.Security.Principal.PrincipalPolicy work under Mono?

Well, NoPrincipal and UnauthenticatedPrincipal behave exactly the same way as they do in the Microsoft implementation. For the WindowsPrincipal the unix groups are used to determine the result of IsInRole. eg:

//lists the groups the user timvw is part of:
//timvw@debian:~$ groups
//timvw dialout cdrom floppy audio video plugdev

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
IPrincipal principal = Thread.CurrentPrincipal;

string[] roles = new string[] { "floppy", "wheel" };
foreach(string role in roles)
{
 Console.WriteLine("{0} is in the {1} role: {2}.", principal.Identity.Name, role, principal.IsInRole(role));
}

// the output:
//timvw@debian:~$ ./Main.exe
//timvw is in the floppy role: True.
//timvw is in the wheel role: False.

How are instances of IPrincipal propgated into other threads?

A bit of research learned me that BeginInvoke and Thread.Start copy the Thread.CurrentPrincipal into the new thread and that ThreadPool.QueueUserWorkItem and System.Threading.Timer don’t copy the Thread.CurrentPrincipal.

How can i use the Authorization Manager without Windows Identity?

A possible solution would be the following:

static string GetSid()
{
 // modify this so that it contains an application and user id
 return "S-1-9-1-1";
}

// By passing in 1 as the second parameter, no verification of the SID against the AD is performed
IAzClientContext cctx = app.InitializeClientContextFromStringSid(GetSid(), 1, null);

// Because the MMC does not allow you to add custom SIDs you'll have to edit to add these manually (eg: by using the API)
IAzApplicationGroup group = app.OpenApplicationGroup("DemoApplicationUsers", null);
group.AddMember(GetSid(), null);
group.Submit(0, null);

// And now you can verify is the custom SID has access to a given operation:
Console.WriteLine(HasAccess(cctx, null, new int[] { 1 }));

static bool HasAccess(IAzClientContext context, string[] scopeNames, int[] operationIds)
{
 string subject = "audit";

 object scopes;
 if (scopeNames == null || scopeNames.Length == 0)
 {
  scopes = new object[] { "" };
 }
 else
 {
  scopes = Array.ConvertAll<string, object>(scopeNames, delegate(string scopeName) { return scopeName; });
 }

 object[] operations = Array.ConvertAll<int, object>(operationIds, delegate(int operationId) { return operationId; });
 object[] results = (object[])context.AccessCheck(subject, scopes, operations, null, null, null, null, null);
 foreach (object result in results)
 {
  if ((int)result != 0)
  {
   return false;
  }
 }

 return true;
}