Archive for September, 2007

New release of my favorite IDE

No Comments »Written on September 18th, 2007 by
Categories: IDE, Software Development

And no, i certainly don't mean Visual Studio :)

The NetBeans team has announced the availability of NetBeans 6.0 Beta 1. It's like Visual Studio with Resharper, only free, open-source, cross-platform AND stable. Oh, and it also has a lot more features. Too bad it doesn't support .NET or it would be my IDE of choice at home. If you're into Java development you really should check it out. They even added Ruby (including Rails) support. And if you only do .NET, check out NetBeans anyway and see what kind of features you'll get in future Visual Studio versions :)

Generic mappers

1 Comment »Written on September 16th, 2007 by
Categories: Software Development

I love using mapper classes to avoid littering my code with ugly if/case statements. These classes simply map a string value to something else, like an enumeration value.

An example of one of the mapper classes in Noma looks like this:

    public static class CascadeOptionMapper
    {
        private static readonly Dictionary<string, CascadeOption> _map = InitializeMap();
 
        private static Dictionary<string, CascadeOption> InitializeMap()
        {
            Dictionary<string, CascadeOption> map = new Dictionary<string, CascadeOption>();
 
            map.Add("none", CascadeOption.None);
            map.Add("save-update", CascadeOption.SaveUpdate);
            map.Add("all", CascadeOption.All);
            map.Add("delete", CascadeOption.Delete);
            map.Add("all-delete-orphan", CascadeOption.AllDeleteOrphan);
 
            return map;
        }
 
        public static CascadeOption GetCascadeOption(string key)
        {
            if (string.IsNullOrEmpty(key) || !_map.ContainsKey(key))
            {
                return CascadeOption.Unknown;
            }
 
            return _map[key];
        }
    }

That's not a lot of code to keep your other code clean, but it does get repetitive if you need to do this for each mapper class. As you can see, the only thing that's not generic about the above class is adding the specific values to the map and returning a default value in case the key can't be found. We can move the other stuff to a generic base class, which would look like this:

    public abstract class ValueMapper<T>
    {
        private readonly Dictionary<string, T> _map;
 
        internal ValueMapper()
        {
            _map = new Dictionary<string, T>();
            RegisterValues(_map);
        }
 
        protected abstract T ValueWhenKeyNotFound
        {
            get;
        }
 
        internal T GetValue(string key)
        {
            if (string.IsNullOrEmpty(key) || !_map.ContainsKey(key))
            {
                return ValueWhenKeyNotFound;
            }
 
            return _map[key];
        }
 
        protected abstract void RegisterValues(Dictionary<string, T> map);
    }

The CascadeOptionMapper class now looks like this:

    public class CascadeOptionMapper : ValueMapper<CascadeOption>
    {
        private static readonly CascadeOptionMapper _instance = new CascadeOptionMapper();
 
        public static CascadeOption GetCascadeOption(string key)
        {
            return _instance.GetValue(key);
        }
 
        protected override CascadeOption ValueWhenKeyNotFound
        {
            get { return CascadeOption.Unknown; }
        }
 
        protected override void RegisterValues(Dictionary<string, CascadeOption> map)
        {
            map.Add("none", CascadeOption.None);
            map.Add("save-update", CascadeOption.SaveUpdate);
            map.Add("all", CascadeOption.All);
            map.Add("delete", CascadeOption.Delete);
            map.Add("all-delete-orphan", CascadeOption.AllDeleteOrphan);
        }
    }

The amount of code hasn't been reduced that much, but it has gotten easier to create a specific mapper now. And now i can easily add my other mapper classes:

    public class PolymorphismOptionMapper : ValueMapper<PolymorphismOption>
    {
        private static readonly PolymorphismOptionMapper _instance = new PolymorphismOptionMapper();
 
        public static PolymorphismOption GetPolymorphismOption(string key)
        {
            return _instance.GetValue(key);
        }
 
        protected override PolymorphismOption ValueWhenKeyNotFound
        {
            get { return PolymorphismOption.Unknown; }
        }
 
        protected override void RegisterValues(Dictionary<string, PolymorphismOption> map)
        {
            map.Add("implicit", PolymorphismOption.Implicit);
            map.Add("explicit", PolymorphismOption.Explicit);
        }
    }


    public class OptimisticLockOptionMapper : ValueMapper<OptimisticLockOption> 
    {
        private static readonly OptimisticLockOptionMapper _instance = new OptimisticLockOptionMapper();
 
        public static OptimisticLockOption GetOptimisticLockOption(string key)
        {
            return _instance.GetValue(key);
        }
 
        protected override OptimisticLockOption ValueWhenKeyNotFound
        {
            get { return OptimisticLockOption.Unknown; }
        }
 
        protected override void RegisterValues(Dictionary<string, OptimisticLockOption> map)
        {
            map.Add("none", OptimisticLockOption.None);
            map.Add("version", OptimisticLockOption.Version);
            map.Add("dirty", OptimisticLockOption.Dirty);
            map.Add("all", OptimisticLockOption.All);
        }
    }

Creating a sortable BindingList

No Comments »Written on September 10th, 2007 by
Categories: WinForms

Suppose you want to bind a collection of your custom objects to a DataGridView in a WinForm, and you want it to be sortable without having to write a lot of code. Once again, using Marc Brooks' DynamicComparer this becomes an easy task. Especially when you combine it with the BindingList class (which is a default implementation of the IBindingList interface):

    public class SortableBindingList<T> : BindingList<T>

    {

        private List<T> _sortableList;

 

        public SortableBindingList(List<T> list)

            : base(list)

        {

            _sortableList = list;

        }

 

        protected override bool SupportsSortingCore

        {

            get { return true; }

        }

 

        protected override void ApplySortCore(PropertyDescriptor property,

                                              ListSortDirection direction)

        {

            string sortExpression = property.Name;

 

            if (direction == ListSortDirection.Descending)

            {

                sortExpression = sortExpression + " DESC";

            }

 

            DynamicComparer<T> comparer =

                new DynamicComparer<T>(sortExpression);

 

            _sortableList.Sort(comparer.Comparer);

        }

 

        protected override void RemoveSortCore() {}

    }

Binding a sortable list to a DataGridView is now as easy as this:

            dataGridView.DataSource = new SortableBindingList<Order>(OrderService.GetAllOrders());

Obviously, the sorting capabilities are pretty basic... only one column at a time, sorting can't be removed, etc... For a lot of scenario's though, this could already be sufficient

ObjectDataSource and sorting collections

2 commentsWritten on September 10th, 2007 by
Categories: ASP.NET

The ObjectDataSource control only supports automatic sorting if you bind it to a DataView, DataTable or a DataSet. If you're binding collections to it, you need to provide your own sorting. Using Marc Brooks' excellent DynamicComparer, this is actually a really easy task. In your ObjectDataSource definition, set the SortParameterName attribute to "sortExpression". Then, implement the ObjectDataSource's SelectMethod like this:

        public List<Order> LoadOrderList(string sortExpression)

        {

            return Sorter.GetSortedList<Order>(OrderService.GetAllOrders(), sortExpression);

        }

And the Sorter class looks like this:

    public static class Sorter

    {

        public static List<T> GetSortedList<T>(IEnumerable<T> collection, string sortExpression)

        {

            List<T> sortedList = new List<T>(collection);

 

            if (!string.IsNullOrEmpty(sortExpression))

            {

                DynamicComparer<T> dynamicComparer = new DynamicComparer<T>(sortExpression);

                sortedList.Sort(dynamicComparer.Comparer);

            }

 

            return sortedList;

        }

    }

And that's all there is to it. Note: you have to make sure the SortExpression attribute of each sortable column contains the correct name of the property containing the data you want to sort on.

ASP.NET control security gotcha

No Comments »Written on September 2nd, 2007 by
Categories: ASP.NET

At work, we have a way of registering ASP.NET controls to be secured based on the current user's application role. Securing the controls happens in the PreRender event of the MasterPage of the application. For a while, it seemed to work pretty good. Then we noticed an important bug: if we registered a control inside a TemplateField of a GridView, the control would lose its security settings when a user clicked on one of the column headers to sort the grid. For instance, if we registered an ImageButton that would delete the current row to be secured, and the current user's role implied that the delete image should not be shown, the image would in fact be invisible. But when the user changes the sorting of the grid, all of a sudden the user can see the image.

I was the lucky one who got to fix the bug. First of all, i want to make it clear that i'm definitely not an experienced ASP.NET developer (i usually try to stay away from the presentation layer). Anyway, after a lot of debugging, i figured out that the GridView's postback events were handled after the PreRender event of the MasterPage was handled. When clicking on a GridView's column headers when sorting is enabled, the control performs a new DataBind. When looking at the source code of the GridView through Reflector, it shows that DataBind deletes the existing child controls and then recreates the new ones. Bingo! Our code set the control to be invisible, and after that, the GridView simply deletes its child controls and recreates it, thereby making our ImageButton visible again.

That took me about 5 hours to figure out. An experienced ASP.NET developer probably would've figured this out much more quickly or even would've avoided the issue by securing the control in a later stage of the page's lifecycle. Anyway, i fixed the bug by assigning a delegate to the PreRender event of each control that had to be secured, and then simply set the correct settings for the control at that time. It didn't feel like a good fix, but i couldn't find anything better at that time. So today i figured i'd play around with that issue at home, and it turns out the solution is actually much simpler and cleaner than what i did at work. The best way is to simply secure the controls in the OnPreRenderComplete method of the Page. This way you're sure that your code is executed after each control has finished its lifecycle. So you can simply hide or disable controls during the OnPreRenderComplete method of the page without worrying that the controls will be destroyed and created again. If you must secure the controls in the MasterPage instead of the Page itself for whatever reason, it's best to simply assign a delegate to the content page's PreRenderComplete event during the MasterPage's Page_Load() method and then secure the content page's controls in the event handler.