Monday, June 23, 2008

Move to Apple hardware

Time for a new laptop was on me and I have been weighing up on which piece of hardware to get. Basically I was considering another Sony Vaio, a Dell, possibly an ASUS and a Mac.

I pretty much discounted Sony as I was not happy with my last purchase which was a Sony. It is hard to put my finger on it but the whole experience was not quite right. It was light, fairly quick had quite a nice screen, but it had quirks. Cut/copy paste never worked properly?!? It –always- took two pastes for anything to actually paste. Often using drag to move or copy something crashed explorer quite often. Start up and shut down was getting pretty slow. On the flip side, when all was running it was fine for developing in VS and SQL, and, general performance for building and running apps was good.

I used to have an ASUS and was always happy with it except for its weight and battery life. To be fair this was mainly because it was a desktop replacement. I did pick up the ASUS laptop for a very good price when I did get it but the brand does not appear to be as popular here in Australia.

Dell just bothers me that it is all online. I know I am in the IT space and even spent many years in the e-commerce space, but I want to touch it, look at it and evaluate it.

15inMacBookPro Which leads me to Apple. The big reason with considering the apple is the feedback I have had. A number of people (that I work with and just read their blogs) have made the shift. Assuming you are and MSDN subscriber, you basically get two platforms for free. You get the confidence of high quality hardware. You also get all those treats that just come with OSX (Gargeband!). The real choice I was left with was which mac to get; MacBook or MacBook Pro? In the end I decided I wanted the slightly higher spec hardware from the MacBook Pro but found it very difficult to justify the large jumps in price for the extras on the higher spec’ed machines ($700 to get0.1 Ghz cpu increase and 215Mb more VRam). I ended up getting the Basic MacBookPro with an upgrade to 4GB of ram. Initial tests on Vista Ultimate running on Bootcamp have a performance index of 5.0 which thumps my old Sony score of 3.4.

Thursday, June 12, 2008

CurrentCulture vs CurrentUICulture

I have been guilty of using the CurrentUICulture where I shouldn’t. I made the assumption that the CurrentUICulture would be the thing I want to use to do things on my UI like formating and displaying a date. *WRONG*!

After one of the guys at work asked me why his FxCop told him off for not passing a IFormatProvider into his string.Format(..) I told him to just pass in CultureInfo.CurrentUICulture. Well I was wrong. We are in Australia and it started formatting his dates as mm/dd/yyyy not dd/mm/yyyy. A quick Google showed me the error of my ways. Basically always just use CultureInfo.CurrentCulture. The CultureInfo.CurrentUICulture is actually used by ResourceManager to identify which resource dictionary to use to show text to the user. Now this is great for Globalization but not to be used for localization. Gee don’t they sound like the same thing….?

WPF updates on Database changes

When using WPF in a smart client environment it always seemed natural that with a local datastore I should be able to listen to data changed events from the database. I have bundled a couple of systems together in a spike* to show that it is possible. Note the style implemented here is only useful where the database has one user (ie a smartclient application).

*spike is my way of excusing awful code.

VisualClue

I have taken the databinding goodness from WPF that automatically updates thanks to INotifyPropertyChanged. I have thrown a little visual clue in to show the data that has been modified. The row that was updated glows yellow.

Next I use a dictionary of WeakReferences in my repository to only hand out pointers to “Customers” in the dictionary. As they are weak references its not a big overhead to store them.

Next I use the service broker technology available from SQL 2005 up. The great thing here is that it is available on SQL Express which is perfect for Smart Client applications. Basically I add a trigger to each table (only customer at the moment) and add all the modifications to a queue as XML data.

Last I have a class that listens to the database called  RepositoryNotification. It basically runs in the background thread and using the Service broker queue technology it waits for triggers to place XML on the queue and then returns it as data. This all works great. At the moment the code that translates the xml is just awful so my apologies up front.

WpfWithBoundRepositoryCache.zip

Note this quick spike currently only supports one row updates at a time (due to my crappy XML de-serialization) and doesn't support inserts or deletes. Inserts and deletes could possibly require some “business logic” to identify if the new row should be shown or the deleted row to be removed.

--Edit

Adam Machanic has a brilliant tutorial on Service broker for those interested. Most of my SQL code was ripped from these tutorials. I think it was supposed to be a 3 part series but I can only find part 1 and part 2.

Thursday, June 5, 2008

CAB Module Configuration

One of the issues we face when developing a composite application is where module specific configuration belongs. There seems to be three approaches to the problem.

  1. Put it all in the shell’s app.config. If this is the answer one may want to question why the application is a composite one.
  2. Have a build task that merges module config into the app.config
  3. Have each module just deal with its configuration in isolation.

Option three is my personal preference as I think this lowers the requirements on possibly already complicated build/deploy routines and gives a level of isolation I associate with a composite application. If we were on the web platform we could just create new application domains for sub domains or sub-directories. How can we give similar isolation for client applications?

The .Net framework give us the ability to get config setting very easily from the executing assembly’s config using good old System.Configuration.ConfigurationManager. (still annoys me that System.Configuration is a seperate assembly to reference).

However using the  ConfigurationManager in the default manner is of no use in the composite application world. We have to look to some of its other features to get what we need.  ConfigurationManager provides a (somewhat misleading) method named OpenMappedExeConfiguration.  It actually allows access to non executable assemblies ie a dll. In this example we use the standard of a “.config” suffix to an assembly name to identify the module config.

    ExeConfigurationFileMap map = new ExeConfigurationFileMap();
    map.ExeConfigFilename = this.GetType().Assembly.Location + ".config";
    if (File.Exists(map.ExeConfigFilename))
    {
        _configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
    }

Now our _configuration variable can be used in a similar fashion to ConfigurationManager. We have access to our old favorite properties AppSettings and ConnectionStrings. We also can get config sections by using the GetSection method.

Hope this little insight helps building your composite applications in a little bit more isolation.

*Thanks to Grae for the base code.

Wednesday, May 28, 2008

Missing WPF Dialog windows

We have been having some fun (read defects raised) with dialog windows in our WPF app. I remember when we wrote the system that showed a custom Warning Message that we wanted it to be displayed modally and not show up in the task bar. Sounds simple so far. However, if I tabbed away from the app and came back to it, the dialog was hiding. Naughty little dialog. Our fix at the time was to set Topmost = true. This just got raised as a defect because it was top most for all apps. A bit of a pain for the users as it covered up other apps (probably the bug tracking system LOL). The fix was really simple and one the makes you feel like a bit of a tool. Window window = new Window(); window.Owner = App.Current.MainWindow; //Or the relevant window. window...... //set other properties. window.ShowDialog(); Now that we don't have an Orphaned window he is so much better behaved. Good little dialog.

Sunday, May 25, 2008

Automatic implementation of INotifyPropertyChanged

Recently I have read a couple of places that are toying with the idea of making property changed events a little bit easier. Serial Seb had some ideas and so has Paul Stovel. My take on it is if we can just decorate the Class or property with an attribute. Either
public class MyClass : INotifyPropertyChanged
{
    [Notify]
    public string MyProperty { get; set;}

    public PropertyChangedEventHandler PropertyChanged
}
or
[Notify]
public class MyClass : INotifyPropertyChanged
{
    public string MyProperty { get; set;}

    public PropertyChangedEventHandler PropertyChanged
}
Now that we have considered the desired outcome we can identify possible options. Both options that come to mind involve something more than just the .Net framework. One option is to use Injectors as Seb showed. My other option is to use PostSharp to inject the code at compile time. I might knock up some tests to see if there is any performance difference. [Update] Here is the code that I shamelessly stole from Seb. It is a post sharp implementation as we don't use Windsor on the project I am on. This code doesn't check if the value actually changed.
[Serializable]
[AttributeUsage(AttributeTargets.Assembly 
    | AttributeTargets.Class 
    | AttributeTargets.Struct 
    | AttributeTargets.Constructor 
    | AttributeTargets.Method 
    | AttributeTargets.Property 
    | AttributeTargets.Event, AllowMultiple = true, Inherited = false)]
public sealed class NotifyAspectAttribute : OnMethodBoundaryAspect
{
    public override void OnExit(MethodExecutionEventArgs eventArgs)
    {
        if (eventArgs == null)
            return;

        //Why are property sets not properties? they are methods?
        if (
            (eventArgs.Method.MemberType & System.Reflection.MemberTypes.Method)
            == System.Reflection.MemberTypes.Method
            &&
            eventArgs.Method.Name.StartsWith("set_")
            )
        {
            Type theType = eventArgs.Method.ReflectedType;
            string propertyName = eventArgs.Method.Name.Substring(4);

            // get the field storing the delegate list that are stored by the event.
            FieldInfo[] fields = theType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            FieldInfo field = null;
            foreach (FieldInfo f in fields)
            {
                if(f.FieldType == typeof(PropertyChangedEventHandler))
                {
                    field = f;
                    break;
                }
            }

            if (field != null)
            {
                // get the value of the field
                PropertyChangedEventHandler evHandler = field.GetValue(eventArgs.Instance) as PropertyChangedEventHandler;

                // invoke the delegate if it's not null (aka empty)
                if (evHandler != null)
                    evHandler.Invoke(eventArgs.Instance, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Wednesday, May 21, 2008

Strong typed CAB events

Out of pure guilt of not posting for 6 months (wow lazy), I thought i had better share some love. Having been in the CAB space for a while and followed the EventTopics constants file pattern we have found that it can get very loosey goosey and have created a new pattern. Only argument less events are defined in the EventTopics constants. Ie anything that just takes EventArgs.Empty goes in here. /// /// Public CAB events that only require empty . /// public class EventTopicNames : MyCompany.Cab.Infrastructure.Interface.Constants.EventTopicNames { /// /// The CAB event string to use to launch a customer search use case. /// /// /// Only need to be provided as the event arguments. /// public const string LAUNCH_CUSTOMER_SEARCH = "MyCompany.Examples.MyCustomerModule.Interface.LaunchCustomerSearch"; } However if you need arguments passed with your event different rules apply. First, never use generic EventArgs. What a stupid idea generic EventArgs are. Take the 30seconds out of your life and create a strongly type event arg. Good practice tells us that in general it should be immutable so you can set the private field backing stores to readonly. Next provide arguments in the constructor to set any properties and then expose the properties. Also, seal the class as I bet no-one will want to inherit from you ultra specific CAB event arg. Now, the event topic name belongs on this class. This now makes the whole thing so much more cohesive and discoverable. public sealed class LaunchCustomerEditEventArgs : System.EventArgs { public const string CAB_ID = "MyCompany.Examples.MyCustomerModule.LaunchCustomerEditEventArgs"; private readonly int _customerId; public LaunchCustomerEditEventArgs(int customerId) { _customerId = customerId; } public int CustomerId { get { return _customerId; } } } Here I have used the convention of "CAB_ID" to expose the event topic name. That is just to satisfy the coding standards for the current company. I would prefer it to be "EventTopicName" . Remember this needs to be constant so that it can be used in attribute on you publications and subscriptions. As it needs to be public and constant, changing it is a breaking change and requires all your dependant assemblies to recompile. To avoid the need to change it please give it a truly unique value. A good option is to use the full type name of the EventArgs.