Saturday, May 17, 2008

As we all know, ASP.NET uses one form model to do all it's magic. Love it or hate it, we have to live with it. 99% of the time, it is not a problem, but then there is this 1%...

The main problem with ASP.NET's model is that the form tag has a fixed action attribute. What if we want to change it? No, there is no simple way of doing it. Solutions vary. Most common one is to create your own FormControl that inherits from HtmlForm and override RenderAttributes method. Unfortunately, inside that method, we have to do everything the original method does and only change the action attribute to the desired value. Ugly!

Another one is to provide an OutputFilter for the Response but that is also a lot of coding.

My preferred way of dealing with this issue is to provide my own, special HtmlTextWriter. Its role is to intercept the WriteAttribute method call and provide my own value. Following code illustrates the concept:

class ActionAttributeWriter
    : HtmlTextWriter
{
    string action;
    public ActionAttributeWriter(
        HtmlTextWriter writer, string action)
        : base(writer)
    {
        this.action = action;
    }
    public override void WriteAttribute
        (string name, string value, bool fEncode)
    {
        if (name == "action")
        {
            value = action; 
        }
        base.WriteAttribute(name, value, fEncode);
    }
}

Only thing that is needed then is to use this writer instead of a normal one. Page.CreateHtmlTextWriter can be used for this purpose:

protected override HtmlTextWriter 
    CreateHtmlTextWriter(System.IO.TextWriter tw)
{
    ActionAttributeWriter writer = 
        new ActionAttributeWriter(
            base.CreateHtmlTextWriter(tw), 
            "action");
    return writer;
}

Solution is not very clean and I would certainly not recommend it for a public product, but it's better than nothing.

Saturday, May 17, 2008 2:09:17 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Saturday, April 05, 2008

Today I needed to add an special field to my LINQ query. A kind of Row Number column. Actually it was not a row number nor was it a column since LINQ deals with objects, but since it was used for presenting data in a tabular way, I see no other name that fits the description.

So, I needed a data displayed in a following format:

Lp. Name
1 Murray N. Rothbard
2 Hans-Hermann Hoppe
3 Ludwig von Mises

First column had to be generated somehow. Using LINQ. I made few quick searches on google, but whith no success, so I came out with my own solution:

int i = 1;
return from author in DataContext.Authors
       select new Author() { Lp = i++, Name = author.Name };

So very simple. Isn't it?

Friday, April 04, 2008 11:15:34 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Wednesday, April 02, 2008

Today while using Reflector I've noticed one funny thing. It came out, that we are able to see where Microsoft keeps their PublicKey files and what are their names :-)

Few samples:

mscorlib f:\RedBits\Tools\devdiv\EcmaPublicKey.snk
System.Data.Linq f:\dd\tools\devdiv\EcmaPublicKey.snk
System.Web f:\RedBits\Tools\devdiv\FinalPublicKey.snk
Microsoft.VisualBasic f:\\RedBits\\Tools\\devdiv\\FinalPublicKey.snk

Nothing special, but... Keep this in mind when doing RTM so you don't something that shouldn't be distributed, like: CustomersIHate\Customer1\Key.snk

Wednesday, April 02, 2008 5:55:40 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Tuesday, April 01, 2008

One thing that I like about SQL is the IN operator which checks if an argument is equal to any of the listed elements. C#/.NET doesn't offer this kind of operator which forces us to use code similar to the one below:

int i = 5;
if (i == 5 || i == 4 || i == 3)
{
    return;
}

Wouldn't it be better if we could just write like this:

if (i.In(5, 4, 3))
{
    return;
}

What we need is a simple Extension Method:

public static bool In<T>(this T source, params T[] values)
{
    return values.Any(v => v.Equals(source));
}

Few things to notice. First I'm using generic type parameter T to avoid boxing for Value Types. Second, it would probably be a wise thing to write few overrides like this:

public static bool In(this IComparable source, params IComparable[] values)
{
    return values.Any(v => v.CompareTo(source) == 0);
}

And another one for generic version. Finally it would be wise to provide an overload that accepts IEqualityComparer, like like LINQ extension methods do.

Whatever you do, you just have to love Extension Methods :-)

Tuesday, April 01, 2008 9:32:49 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, March 29, 2008

There is a nice little base class hidden inside System.Collections.ObjectModel namespace. Its name is KeyedCollection. Its there to solve all those situations when we need a collection where items are to be unique, a "collection whose keys are embedded in the values" - as MSDN describes it.

As nice as the class is, there is one problem. It is abstract. The reason it is abstract is the GetKeyForItem method. For each type what we need a unique collection, we need to create a new class, inherit it from the KeyedCollection and override that one method. I think that's a bit of a waste of time and needles complexity in most cases. Fortunately, there is hope.

Enter KCollection. The idea behind it is to use Lambda Expressions where we had to override the GetKeyForItem method before. Sample code should explain everything:

class KCollection<TKey, TItem>  : KeyedCollection<TKey, TItem>
{
    Func<TItem, TKey> getKey;
    public KCollection(Func<TItem, TKey> getKey)
    {
        this.getKey = getKey;
    }
    protected override TKey GetKeyForItem(TItem item)
    {
        return getKey(item);
    }
}

And usage looks as follows:

KCollection<int, Client> kcol = new KCollection<int, Client>(c => c.Id);

Where Client is a simple class:

class Client
{
    public int Id;
    public string Name;
}

Of course we could achieve similar functionality using .NET 2.0 and delegates, I think Lambda Expressions are just nicer.

Saturday, March 29, 2008 2:44:47 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 

I've never liked VB.NET. Probably because I was (un)fortunate enough to work with VB6 for 2 years, even though .NET and C# were already there. Nevertheless I'm aware that VB.NET tends to offer some very useful syntax not found in C#.

One thing that I've recently discovered is the ability to specify a "Key Properties" when defining an Anonymous Type.

Syntax for the declaration is more or less as follows:

Dim person = New With {Key .Id = 1, .Name = "John"}

Notice the Key keyword before Id property. Now the interesting thing is that VB.NET compiler generates the Equals method that compares objects for equality, using only the Key Properties as opposed to comparing all properties when code is generated by C# compiler.

Now tell me that VB.NET is slower than C#.

More on the topic can be found on MSDN article on Anonymous Types in VB.NET, in section on Key Properties of course.

Saturday, March 29, 2008 11:59:11 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, March 14, 2008

Internet Explorer Enhanced Security Configuration - don't you just love it?

Is there anything worse that Microsoft has given us over last few years? I really doubt it.

Friday, March 14, 2008 5:29:12 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Wednesday, December 05, 2007

When I first installed Windows Vista with IIS 7 I have started to notice that ASP.NET debugger tends to time-out very often. Previously I hadn't noticed such a behavior when I was using Windows 2003 with IIS 6. I really cannot tell if it was there or not, because I sometimes tend to dismiss this kind of issues if they are not very painful.

Sometimes however the debugger timeout IS painful. Fortunately the problem is easily solved. I have found the solution provided by jshallard on ASP.NET's forum:

In IIS 7 go to the Application Pools and select the Advanced Settings for the pool which you process runs in. In the Process Model section you can do one of two things;
    * Set the Ping Enabled property to False. This will stop IIS checking to see if the worker process is still running and keep your process alive permanently (or until you stop your debugged process)
    * If you prefer to allow IIS to continue the monitoring process then change the Ping Maximum Response Timeout value to something larger than 90 seconds (default value).

I've tried the second option and it worked.

Wednesday, December 05, 2007 7:06:45 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [4]  | 

As hard as it is for me to believe, there are people out there that do not use the Total Commander! Yes, that is true. Those people use the built in Windows Explorer for navigating folders, copying files and all other things. Their main argument for doing it, is that "sometimes I may find myself in a situation where there is not Total Commander and I want to be prepared". Sometimes I also find myself in this kind of situation and what I find that I almost always miss is the ability to easily start a command line in a specified folder.

A typical situation is when there is some kind of application and it comes with a command line tools. In order to run those tools, we obviously need a command line - to display help text if nothing else. Without Total Commander, we are more or less forced to do a cd XXX few times.

More advanced users know the CMD command a little better and they just copy the folder path from the Explorer Window and do something like:

Start->Run->cmd /K cd XXX 

Where XXX is the path of the destination folder. This unfortunately not only requires a couple of steps, but also a few things to remember. The easier way is to make it possible to launch a command line by just selecting the right option from the context menu.

To make such an option available, just open Regedit.exe, navigate to:

HKEY_CLASSES_ROOT\Folder\shell

Create a new Key there, such as CmdHere. Set the value of a (Default) entry to some friendly text like "Cmd Here". Next, create a new command key and set the value of a (Default) entry to "cmd /K cd %1".

You should now be able to see a new option in the context menu, when you click on a folder.

Wednesday, December 05, 2007 6:58:14 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 

There is a nice control in ASP.NET called ValidationSummary. Its purpose is to group and display all validation error messages in one place. Errors reported by Validator controls put on the page are displayed there. This is a standard way we all use ValidationSummary. Sometimes however, there is a need for presenting some kind of error found on the server side.

After investigation, I have found that there is no easy way of adding errors to the ValidationSummary. That is because the ValidationSummary control reads error messages directly from the page by means of iteration over all validators it gets by calling Page.GetValidators() method. Since none of the crucial methods is virtual, there is no way of customizing the standard behavior by means of inheritance.

This time rather than fighting/hacking ASP.NET once again, I've decided, to use it's own weapons against it. It came out as a rather clean solution. In order to add your error message to a ValidationSummary control you can add a validator to a Validators collection of the page. But which one to use? None of the standard ones since they all inherit from a Label (!?!?!).

It comes out, that ValidatorCollection's (that is the type of Validators property) Add method is one of those few .NET methods that operates using interfaces rather than concrete classes. This particular method accepts an IValidator interface. What we need then is a special CustomError class that looks like this:

public class CustomError : IValidator
{
    private string errorMessage;

    public CustomError(string errorMessage)
    {
        this.errorMessage = errorMessage;
    }

    public string ErrorMessage
    {
        get
        {
            return errorMessage;
        }
        set
        {
            throw new NotSupportedException();
        }
    }

    public bool IsValid
    {
        get
        {
            return false;
        }
        set
        {
            throw new NotSupportedException();
        }
    }

    public void Validate()
    { }
}

Now using this class is dead simple. Once we need to add an error to the summary, we do the following:

Validators.Add(new CustomError("Error Message"));

The only problem is that if the error is to persist between postbacks, we have to add the new validator every time.

Wednesday, December 05, 2007 6:40:47 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  |