12/15/2004

Holiday Greetings:

I recently received the below Holiday Greeting from a compatriot, and decided to post it. No explanation should be needed:

Dear XXX:


With the holidays fast approaching and EULAs pretty much a fact of life, please accept -- with no obligation, implied or implicit, on behalf of the wisher or wishee -- my best wishes for an environmentally-conscious, socially-responsible, low-stress, non-addictive, gender-neutral celebration of the winter solstice, practiced within the traditions and/or within the religious or secular belief(s) of your choice and with respect for the traditions and/or religious or secular beliefs of others or for their choice to not practice traditions and/or religious or secular beliefs at all; and for a fiscally-successful, personally-fulfilling, medically-uncomplicated recognition of the onset of what is generally accepted as the new Gregorian calendar year, but with due respect for calendars of other cultures whose contributions to society have helped make America great*, and without regard to the race, creed, color, age, physical ability, sexual orientation, political affiliation, or choice of computer operating system of the wisher.



DISCLAIMER

By accepting this greeting you are accepting the terms of the greeting and all responsibility associated with it. This greeting is subject to clarification and/or revocation at any time at the discretion of the wisher. This greeting is non-transferable without the express written consent of the wisher. It implies no promise by the wisher to actually implement any of the wishes for him/herself or for others. This greeting is warranted to perform as expected within the usual application of good tidings for a period of one year or until the issuance of a subsequent holiday greeting, whichever comes first. Warranty is limited to replacement of this greeting or issuance of a new greeting at the sole discretion of the wisher, who assumes no responsibility for any unintended emotional stress this greeting may bring to those not caught up in the holiday spirit.

By accepting this greeting you agree to subscribe to annual updates at a cost completely arbitrary to the wisher at the time of renewal. Failure to subscribe - in effect, failure to renew this greeting - will result in forfeiture of the original greeting, loss of your parents' homes, euthanasia for your and your neighbors' pets, and prosecution in a kangaroo court of law comprised of the wisher's closest friends and paid business associates, convened by the wisher at a location deemed most inconvenient to you. Reading of this disclaimer constitutes your acceptance of the greeting. Oh, and I almost forgot...this disclaimer supersedes all local, state and federal laws previously enacted to prevent such disclaimers from superseding all local, state and federal laws.

* -- This does not imply that the United States of America is necessarily greater than any other country, or that it is the only America in the western and/or eastern hemispheres.


12/13/2004

ASP.NET v1.1 Member Management Component Prototype

Checkitout:

http://www.asp.net/MemberRoles/memberroles.htm

12/07/2004

Server 2003 SP1 Release Candidate available NOW!

Here it is!

http://www.microsoft.com/downloads/details.aspx?FamilyID=ae20c29d-5c71-49ce-9091-3aedc9e5979f&DisplayLang=en

Need to Get A HEAD?

This nice little piece was recently posted by David Kline on his blog:

Have you ever wanted to know what type of file was being pointed to by a given url before clicking the link?  Maybe you are writing an application that needs to filter out certain types of links.  A web crawler is a good example of an application which needs to do such link filtering (skip links to graphics, audio, zip files, etc).

In order to check the type of data pointed to by a url, you are going to need to issue a request to the server.  Normally, this involves receiving the entire page or file at that location.  This can be a time consuming proposition, especially over slow network connections, and defeats the purpose of allowing your application to filter out undesired links.

The solution is to issue a request to the server, asking only for the HTTP headers.  This "HEAD" request is small, fast (does not transfer file contents) and provides you with exactly the data your application needs.  While there are plenty of interesting headers, the header we are interested in today is "Content-type".

Below is a simple console application that takes a url path and displays the value of the content-type header.  Please note: To keep this example as small as possible, only minimal error checking is performed - any real-world implementation would need to do much more than what I show here.

using System;
using System.Net;

class ContentType
{
    public static void Main(String[] args)
    {
        if(args.Length != 1)
        {
            Console.WriteLine("Please specify a url path.");
            return;
        }

        // display the content type for the url
        String url = args[0]; 
        Console.WriteLine(String.Format("Url : {0}", url));
        Console.WriteLine(String.Format("Type: {0}", GetContentType(url)));
    }

    private static String GetContentType(String url)
    {
        HttpWebResponse response = null;
        String contentType = "";

        try
        {
            // create the request
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            // instruct the server to return headers only
            request.Method = "HEAD";

            // make the connection
            response = request.GetResponse() as HttpWebResponse;

            // read the headers
            WebHeaderCollection headers = response.Headers;

            // get the content type
            contentType = headers["Content-type"];
        }
        catch(WebException e)
        {
            // we encountered a problem making the request
            //  (server unavailable (404), unauthorized (401), etc)
            response = e.Response as HttpWebResponse;

            // return the message from the exception
            contentType = e.Message;
        }
        catch(NotSupportedException)
        {
            // this will be caught if WebRequest.Create encounters a uri
            //  that it does not support (ex: mailto)

            // return a friendly error message
            contentType = "Unsupported Uri";
        }
        catch(UriFormatException)
        {
            // the url is not a valid uri
           
            // return a friendly error message
            contentType = "Malformed Uri";
        }
        finally
        {
            // make sure the response gets closed
            //  this avoids leaking connections
            if(response != null)
            {
                response.Close();
            }
        }

        return contentType;
    }
}

The above code can be compiled and run on either the .NET Framework or the .NET Compact Framework.

Here's a sampling of the content types I received when running the above application against a handful of urls:

text/html
text/html; charset=utf-8
image/gif
application/octet-stream
text/plain

Enjoy!
-- DK

Disclaimer(s):
This posting is provided "AS IS" with no warranties, and confers no rights.

[Microsoft WebBlogs]

12/03/2004

Web Services Enhancements 2.0 SP2 (WSE 2.0 SP2) Released today


This release fixes some top customer issues and provide a new security token, KerberosToken2, which supports impersonation, windows constrained delegation.  The new token also works well with the web farm scenario.

Download WSE2 SP2 from

http://msdn.microsoft.com/webservices/building/wse/default.aspx



IsNumeric in C#? Not!

Recently we had another "go around" at the office regarding IsNumeric in C#. We had a forum discussion on this at eggheadcafe.com some time ago, I suggested to use the Microsoft.VisualBasic.Information.IsNumeric method, which can certainly be called from C# or any other .NET language.

Two other developers, both of whom I highly respect, have gone quite a bit deeper into this; J. Ambrose Little here and Justin Rogers here. Only Rogers actually made reference to the fact that the VisualBasic method does a significant amount of type-checking under the hood; type-checking that was not included in either of their test suites. The bottom line is this:
If I put "$1,079.51" into Ambrose's VisualBasic method, it returns true, because that string, indeed, "IS" numeric. Other methods tried will either incorrectly return false, or will actually hang and not return at all. According to the Microsoft definition of "Numeric", depending on the CultureInfo, any valid Currency sign or thousands / decimal delimiter in the correct position in a string of numbers
should be able to be handled by the method.

My point is, comparative test suites designed to illustrate performance are only valid when comparing apples to apples. If the test methodology or assumptions are initially flawed, their validity goes down the toilet, IMHO. Developers who aren't aware of all these little nuances may very well read one of these blogs/articles and proceed to create their own "IsNumeric" method in C# that uses char.IsDigit and other techniques for speed. And when they ship a French version of their app to a client, it may very well blow up. So, the question is, if you are a C# purist, you could spend a very long time writing your own method and never calling into the Microsoft.VisualBasic.dll assembly. But, since you would have to do all the very same things done in the decompiled code below in order for it to be "right", it might end up not being any faster at all!

ISNUMERIC - decompiled to C# (Not all methods used are shown):


public static bool IsNumeric(object Expression)

{

bool flag1;
IConvertible convertible1 = null;
if (Expression is IConvertible)
{
convertible1 = (IConvertible) Expression;
}

if (convertible1 == null)
{
if (Expression is char[])
{
Expression = new string((char[]) Expression);
}
else
{
return false;
}
}

TypeCode code1 = convertible1.GetTypeCode();

if ((code1 != TypeCode.String) && (code1 != TypeCode.Char))
{
return Utils.IsNumericTypeCode(code1);
}

string text1 = convertible1.ToString(null);

try
{
long num2;
if (!StringType.IsHexOrOctValue(text1, ref num2))
{
double num1;
return DoubleType.TryParse(text1, ref num1);
}
flag1 = true;
}
catch (Exception)
{
flag1 = false;
}
return flag1;
}


internal static bool IsNumericTypeCode(TypeCode TypCode)
{
switch (TypCode)
{
case TypeCode.Boolean:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
{
return true;
}
}
return false;
}



internal static bool TryParse(string Value, ref double Result)
{
bool flag1;
CultureInfo info1 = Utils.GetCultureInfo();
NumberFormatInfo info3 = info1.NumberFormat;
NumberFormatInfo info2 = DecimalType.GetNormalizedNumberFormat(info3);
Value = StringType.ToHalfwidthNumbers(Value, info1);
if (info3 == info2)
{
return double.TryParse(Value, NumberStyles.Any, info2, out Result);
}

try
{
Result = double.Parse(Value, NumberStyles.Any, info2);
flag1 = true;
}

catch (FormatException)
{
flag1 = double.TryParse(Value, NumberStyles.Any, info3, out Result);
}
catch (Exception)
{
flag1 = false;
}
return flag1;
}

internal static CultureInfo GetCultureInfo()
{
return Thread.CurrentThread.CurrentCulture;
}

internal static NumberFormatInfo GetNormalizedNumberFormat(NumberFormatInfo InNumberFormat)
{
NumberFormatInfo info2;
NumberFormatInfo info5 = InNumberFormat;
if (((((info5.CurrencyDecimalSeparator != null) && (info5.NumberDecimalSeparator != null)) && ((info5.CurrencyGroupSeparator != null) && (info5.NumberGroupSeparator != null))) && (((info5.CurrencyDecimalSeparator.Length == 1) && (info5.NumberDecimalSeparator.Length == 1)) && ((info5.CurrencyGroupSeparator.Length == 1) && (info5.NumberGroupSeparator.Length == 1)))) && (((info5.CurrencyDecimalSeparator[0] == info5.NumberDecimalSeparator[0]) && (info5.CurrencyGroupSeparator[0] == info5.NumberGroupSeparator[0])) && (info5.CurrencyDecimalDigits == info5.NumberDecimalDigits)))
{
return InNumberFormat;
}
info5 = null;
NumberFormatInfo info4 = InNumberFormat;
if ((((info4.CurrencyDecimalSeparator != null) && (info4.NumberDecimalSeparator != null)) && ((info4.CurrencyDecimalSeparator.Length == info4.NumberDecimalSeparator.Length) && (info4.CurrencyGroupSeparator != null))) && ((info4.NumberGroupSeparator != null) && (info4.CurrencyGroupSeparator.Length == info4.NumberGroupSeparator.Length)))
{
int num3 = info4.CurrencyDecimalSeparator.Length - 1;
int num1 = 0;
while (num1 <= num3)
{
if (info4.CurrencyDecimalSeparator[num1] != info4.NumberDecimalSeparator[num1])
{
goto Label_019D;
}
num1++;
}
int num2 = info4.CurrencyGroupSeparator.Length - 1;
for (num1 = 0; num1 <= num2; num1++)
{
if (info4.CurrencyGroupSeparator[num1] != info4.NumberGroupSeparator[num1])
{
goto Label_019D;
}
}
return InNumberFormat;
}
info4 = null;
Label_019D:
info2 = (NumberFormatInfo) InNumberFormat.Clone();
NumberFormatInfo info3 = info2;
info3.CurrencyDecimalSeparator = info3.NumberDecimalSeparator;
info3.CurrencyGroupSeparator = info3.NumberGroupSeparator;
info3.CurrencyDecimalDigits = info3.NumberDecimalDigits;
info3 = null;
return info2;
}