Monday, August 18, 2008
Hi all, there's an Architecture chat this Thursday - 21st August @ 11:30am onwards.

Some things that I've caught my eye since last time:
  • .Net 3.5 SP1 and VS2008 RTM are here
  • VS2K8SP1 and SQL2K8 installs are a big mixed bag, some people no problem, other tearing hair out!
  • And so are the war stories such as regressions and critical changes - doh!
  • Visibility and trouble with non-developers being unable to quantify the quality of developer outputs - sparked off by this post by Casey.
  • Resharper 4.01 RC1 is out.
  • ASP.NET MVC now and in the future (i.e. where it's going, and perhaps a discussion on future of monorail vs. MVC and Monorail 2??).
  • Security practices on MVC, WCF etc.
  • Redmine - an interesting (and nicer) alternative to Trac - wonder if there's an easy transition path for existing Trac sites?
Edit: updated this list with some suggestions from others.

If anyone has any topic suggestions - just make a post on this entry, or send me an email / IM message.

Details of previous posts and directions etc. can be found here on the wiki.

posted @ Monday, August 18, 2008 10:47:10 AM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
Here's the write-up for Architecture Chat #32 (from Thursday 7th August 2008) ... some of the things we discussed:
  • Jabl / Jass  (Javascript abstraction language) - we discussed this approach of writing languages that transform into another language - the tradeoffs of debug experience vs. productivity etc.
  • Debug experiences in DSL's and in particular the lack of support in these language rewriting/transformation projects.
  • The magic bullet language i.e. two-way debugging experience, language independent refactoring support, modular/pluggable language support (sorta like Boo).
  • Code camp at the end of this month.
  • Self explaining code / blaming code (i.e. code that can explain the decisions it makes in english, or at least identify the blame (i.e. steps) that lead to the result it selected.  Though we didn't bring it up, I quite like the way Rhino Security does this.
  • xUnit thoughts after a month of using it on a commercial project.
  • Ice ZeroC - WCF alternative?
  • Sql Server partitioned tables, and the simpler query plans / improvements in 2008.
See the wiki for write up's of previous chats, thanks to all those who attended.

posted @ Monday, August 18, 2008 6:22:54 AM (New Zealand Standard Time, UTC+12:00)    Comments [4] | Trackback |
 Friday, August 15, 2008
Yesterday afternoon I presented a quick 20 minute presentation to the Enterprise Architect user group - it was an interesting opportunity to talk with both an Enterprise Architect lead developer and analysts/BA's etc. who are using Enterprise Architect on a daily basis - there's nothing quite like doing something and then even more so presenting on what you've done to really firm up some conclusions / ideas around it (and as is often the case with me, spark 20 ideas for new products I could build to make it better/smarter).

For anyone who's interested here's the slide deck I presented - and also some links to things that were discussed:
Thanks to catch for hosting the group and providing the video conferencing facilities to link Auckland / Wellington (small tip, if you are presenting to two groups be sure to sit at the end of the table looking towards the camera, or your spend your whole time ping-ponging your head towards one group and the other ;) - and also thanks to everyone who came along and listened.

Also of interest was the discussion after the presentation around providing a number of example/sample MDA transformations through Sparx Systems New Zealand site - which should mean that before the end of the year you will be seeing both guidance and examples on developing MDA transformations targeting NHibernate, NHibernate search, ActiveRecord, Monorail and RhinoSecurity starting to emerge (what I tend to loosely call the "Castle stack" for want of a better term.) - which I'll post about it as it starts to happen.

posted @ Friday, August 15, 2008 2:19:21 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Wednesday, August 06, 2008
There's a few things going on in Auckland over the next month or so, just to summarize if you haven't been paying attention :)
So plenty of things going on!

I would suggest signing up for the code camp sooner rather then later if you don't want to miss out - also if you know of any other events that I've left off this list, drop me a comment and I'll add them to it.

posted @ Wednesday, August 06, 2008 7:23:04 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Wednesday, July 23, 2008
So I see more people rewriting my container tutorials lately...

First we have the unity tutorials - as covered by Michael McGuire... which I mentioned a while back.

Now we have the binsor tutorials which have sprung up lately - from ruprict covering the same concepts, but with Binsor syntax - which is quite handy for those that are boo-inclined!

I also believe a set of Ninject tutorials are being written by Simone Chiaretta (codeclimber) in his spare time as well (and who is not jealous of Ninject's website! ;o)

It's encouraging to see interest still growing in IoC on the .Net Framework.

 |  |  |  | 
posted @ Wednesday, July 23, 2008 1:42:46 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Monday, July 14, 2008
Looks like I've been tagged twice - so here goes.

How old were you when you first started programming?

Apple II e when I was like 7, Vic20 when I was like 8... but really my start was about 10 with GW-Basic on a 286 AT 16mhz.

How did you get started in programming?

I was interested in programming from about age 6 or 7.. though I think I was 12 when I taught myselfTurbo C++ (And the object oriented concepts that went with it) - so I've spent over half my life in object oriented languages - not sure if that's good or bad! 

I owe my parents a large amount of gratitude as they recognized my interests early on, and though we had little money they spent a lot trying to encourage my interests (computers were not so cheap in the 80's).

What was your first language?

Basic on the Apple II e and Vic20 - but really I think it wasn't until GW-Basic in Dos4 (and later quick basic) that I became fluent at writing programs and starting to break problems out into a series of functions. After basic came C++ (and in-line assembler), Tcl/Tk and Visual Basic 3 or 4 - then once I started tertiary study I added Pascal, Delphi, Jade, bash, java and perl to the list.

What was the first real program you wrote?

A "real" program ... I'm going to take "real" as something commercial with "users" ... hmm.. I had a part-time job when I was like 14 helping to add functionality to a C based DOS accounting system used around New Zealand - That'd be the first "real" program I added code to.  Around 17 I started writing a lot of code for open source projects [same time I started studying at Unitec] (I think all the projects are dead and gone now) and had a keen interest in writing libraries for game development prior to the advent of hardware accelerated 3D, later transferring that interest to OpenGL once Voodoo and NVidia hardware started getting cheaper.

What languages have you used since you started programming?

Basic (at least 4 or 5 variants), C, C++, Tcl/tk, Bash, Pascal, Jade, Java, JavaScript, Python, Ruby, ASP, T-SQL, Visual Basic 3 and above, VB.Net, F#, VBA, Lisp, Perl, Boo and a few others - though C# has been my language of choice since the early beta's of the .Net Framework v1.

What was your first professional programming gig?

I think probably working as a Junior at Terabyte Interactive (when they were based in Newmarket) on a rowing machine C++/OpenGl visualization app (the infamous RowPro project).

If you knew then what you know now, would you have started programming?

Without a doubt - I was passionate about it when I was 8... I'm still passionate about it after 20 years. It scratches 2 itches I've had my entire life, a need to create and a need to debate/discuss/analyze problems/challenges.

If there is one thing you learned along the way that you would tell new developers, what would it be?
Learn to learn, and if you don't like learning find a new profession.  I almost feel like learning is my job, and developing solutions is a side-effect of trying to achieve my primary objective of learning.

What's the most fun you've ever had ... programming?

Hmm... I couldn't pick any one project - most fun environment-wise would be my early days a Terabyte, it had a wonderful dot-com feel, and we didn't have much work on (at times), so we got to pursue our own pet projects and take long team breakfasts in the local cafe - A fun environment, albeit a doomed one.

Probably since then I would say the "Syzmk Rich Media Processor" - an application which had a wonderful variety of requirements and an interesting suite of technologies (it was developed with early releases of the Castle project and betas of the .Net Framework 2.0) and was one of the first projects I approached in a TDD fashion.

Who’s next?

posted @ Sunday, July 13, 2008 8:47:44 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Monday, June 30, 2008
Jonathon Rossi over in Brisbane has been hard at work on the CVSI project (Castle Visual Studio Integration) and has released version 0.3 which now supports VS 2008 - for those not in the know CVSI provides nvelocity intellisense when writing views for monorail.

I did some testing of some earlier releases last week and it's looking good, hilights include:
  • New installer which supports 2005 and 2008.
  • Basic XHTML intelisense.
It also includes some fixes which means the intelisense now works when the templates are not in a web application project (useful for those of us writing applications where we have pluggable modules) and fixes for multi-level inheritence, so helpers and view components with multiple levels of base class i.e. FormHelper (which now inherits from AbstractFormRelatedHelper) will be included in the list of classes, something which bugged me with earlier releases on 2005.

Great work Jono!

posted @ Monday, June 30, 2008 8:31:14 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Thursday, June 19, 2008
If you recall many moons ago I posted a series of articles on the Castle Project's IOC Container "Windsor" teaching the fundamentals of IoC with a practical bent - lots of people liked them, and I still get feedback every now and then from people starting to use windsor and finding them useful.

At any rate Michael McGuire was once such person who read those tutorials a year or so ago and has now started a series of his own - mirroring my castle container tutorials but with the P&P Unity container instead - you can find it here.

As someone who has not given Unity much more then a brief skim it's a nice way to quickly get up to speed on some of the key differences.

So far after reading a couple of articles I've learnt.
  • You need to implement your own type converters for things like arrays or dictionaries in configuration.
  • Configuration syntax is not particularly human-friendly, obviously designed for management via a tool  - requiring the entry of full types all over the spot like "Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration" - just to register a component!
  • Default lifestyle is transient... hmmm.. personally I think singleton is more-often the norm for me when writing applications, but it really depends on how the container is being used/abused I guess.
  • Support for multiple configurations looks a little more baked in - but this is trivial stuff to implement in most containers.
I'll be interested to see how decorator chains etc. are implemented in Unity.

Good work Michael.

 |  |  | 
posted @ Thursday, June 19, 2008 12:45:04 AM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
 Saturday, June 14, 2008
splicer_1000.PNG
Version 1.0.0.0 of splicer (the little video/audio composition library that leverages DirectShow which I started a few years ago) is now available on Codeplex here this marks a milestone in stability, and probably the main "feature" of this release is 64bit support, something that's been bugging me for ages as I could only work on the project in a VM!

A quick list of changes since the last release are:
  • Now uses DirectShow.Net 2.0 (thanks to felix, a fellow NZ'r).
  • RenderProgress event.
  • Renderers are disposable.
  • Support for 64bit operating systems.
  • Vista fixes/support.
  • Additional samples (i.e. SampleTimeWatermarkParticipant, and a few others).
  • Tests updated for NUnit 2.4.7.
  • Solution upgraded to VS2008.

What's splicer?

With this library and a little imagination you can:
  • Encode video or audio suitable for use on a website.
  • Create slide shows from images, videos and audio.
  • Apply effects and transitions to audio and video.
  • Grab System.Drawing.Image clips from a video at certain times.
  • Modify individual video frames during encoding via standard C# mage Drawing code.
  • Add new soundtracks to existing video clips.
  • Watermark videos.
  • Build a video editing suite, if you were so inclined.





posted @ Friday, June 13, 2008 12:37:47 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Wednesday, June 11, 2008

DevDefined.OAuth

I have a first release of my OAuth implementation up on google code, you can read a little more about it here and the code can be found here.  It's released under the MIT license, basically do what you like with it.

The library includes both consumer and a provider implementations - test coverage is pretty poor, as it was originally put together as part of my REST presentation to the local Ellerslie .Net user group a few weeks ago, but as I work through the code and rewrite various sections in my spare time it should become a little more robust.

If you're serious about using this code then I would suggest reviewing the OAuth core spec 1.0 and the OAuth problem reporting extensions.

The OAuth wiki and google group are also great places to learn more about OAuth.

I have not added the MonoRail examples back to the code yet - but will shortly - and will probably provide a WCF implementation as well.

I've also posted a short intro to OAuth - OAuth for beginners - for those who are interested.
posted @ Tuesday, June 10, 2008 7:37:58 PM (New Zealand Standard Time, UTC+12:00)    Comments [1] | Trackback |
 Wednesday, February 20, 2008
So a few weeks back there was a post on the Genome TeamBlog which included a link to one of my lambda abuse posts from last year.

At any rate - the problem they faced was that with code like this:

DataContext Context = new DataContext();

string connStr = "";

 

DataDomainSchema schema = DataDomainSchema.LoadFrom("SomeMappingFile");

schema.CreateDbSchema(connStr);

 

DataDomain dd = new DataDomain(schema, connStr);

 

using (Context.Push(ShortRunningTransactionContext.Create()))

{

    Customer tt = dd.New<Customer>();

    tt.Name = "TechTalk";

 

    RootProject tt_hk = dd.New<RootProject>();

    tt_hk.Name = "Housekeeping";

 

    ChildProject tt_hk_hol = dd.New<ChildProject>();

    tt_hk_hol.Name = "Holiday";

    tt_hk.ChildProjects.Add(tt_hk_hol);

 

    ChildProject tt_hk_ill = dd.New<ChildProject>();

    tt_hk_ill.Name = "Illness";

 

    tt_hk.ChildProjects.Add(tt_hk_ill);

 

    tt.RootProjects.Add(tt_hk);

 

    RootProject tt_g = dd.New<RootProject>();

    tt_g.Name = "Genome";

 

    ChildProject tt_g_dev = dd.New<ChildProject>();

    tt_g_dev.Name = "Development";

    tt_g.ChildProjects.Add(tt_g_dev);

 

    ChildProject tt_g_mnt = dd.New<ChildProject>();

    tt_g_mnt.Name = "Maintenance";

    tt_g.ChildProjects.Add(tt_g_mnt);

    tt.RootProjects.Add(tt_g);

 

    Context.CommitCurrent();

}


You ended up with a very flat member initialization structure plagued with:
  • Having to explicitly name child instances being added to collections - there's a lot of unnecessary noise.
  • Where you can't easily see the structure i.e. it's not visually hierarchical, so at a glance you're not sure just what the structure is compared to say looking at an xml document with nested elements where it's quite obvious.
At any rate, the guys at the Genome project attempted to overcome this using the nested lambdas (what I coined a "DSL" at the time, though It's a terrible and inaccurate term for what's effectively just a bit of a "trick" relying on side effects of evaluation) - it didn't go so well though because of course at first glance the syntax look strongly typed, the reality is it's anything but, and refactoring tools just aren't going to do things like renaming of keys in the hash style syntax i.e. key => value, because the key is just a Lambda parameter.

But all is not lost - of course with C# 3.0 we already have a great syntax for doing this kind of hierarchical initialization, say for this set of types:

public class BlogPost

{

    private readonly List<string> _tags = new List<string>();

    private readonly BlogUser _createdBy = new BlogUser();       

 

    public string Title { get; set; }

 

    public string Body { get; set; }

 

    public List<string> Tags

    {

        get { return _tags; }

    }

 

    public BlogUser CreatedBy

    {

        get { return _createdBy; }

    }

 

    public BlogUser LastEditedBy { get; set; }

}

 

public class BlogUser

{

    public int Age { get; set; }

    public string Name { get; set; }

}


We could do something like this to initialize an instance of BlogPost:

BlogPost post = new BlogPost()

{

    Title = "Post on Lambdas",

    Body = "This is a post...",

    Tags =

    {

        ".Net",

        "Lambda",

        "C#3.0"

    },

    CreatedBy =

    {

        Name = "Jane Doe",

        Age = 35

    },

    LastEditedBy = new BlogUser()

    {

        Name = "Joe Bloggs",

        Age = 25

    }

};


But the catch for the Genome guys is that it looks like they need to construct their entities using their DataDomain class ...  I don't know about how there product works but I can only assume it's either to get a transparent proxy for change tracking purposes or to enlist it into the current session etc. (though if it's just to enlist the entity I can't see why they need to bother with getting the DataDomain to create a new instance, surely they could manually enlist it).

At any rate that's irrelevant :)

So I got to thinking that of course member initialization is one of the Lambda-friendly things we can do because it's expressed in a single statement - so we can happily take the above code snippet and express it like so:

BlogPost post = evaluator.Create(() => new BlogPost()

{

    Title = "Post on Lambdas",

    Body = "This is a post...",

    Tags =

    {

        ".Net",

        "Lambda",

        "C#3.0"

    },

    CreatedBy =

    {

        Name = "Jane Doe",

        Age = 35

    },

    LastEditedBy = new BlogUser()

    {                   

        Name = "Joe Bloggs",

        Age = 25

    }

});


Where evaluator is an instance of a class I wrote called ServiceInjectionEvaluator ... the Create method (as you can probably guess) has the following signature:


  public
T Create<T>(Expression<Func<T>> expression)


The service injection evaluator just relies on being configured with an IServiceProvider capable of resolving instances of types... at this point we just unwind the expression, substituting our own instance activation mechanism wherever we stumble upon a NewExpression and walking through the expressions executing each bit as required - though it makes the assumption that you're going to have either a New or MemberInit expression at the top level of the Lambda, otherwise we just compile the whole thing and throw it back without any changes (because I don't want to bother writing code to visit the other types of expression node).

public class ServiceInjectionEvaluator

{

    private readonly IServiceProvider _serviceProvider;

 

    public ServiceInjectionEvaluator(IServiceProvider serviceProvider)

    {

        _serviceProvider = serviceProvider;

    }

 

    public T Create<T>(Expression<Func<T>> expression)

    {

        switch (expression.Body.NodeType)

        {

            case ExpressionType.New:

            case ExpressionType.MemberInit:

                return (T)EvaluateExpression(expression.Body);

            default:

                return expression.Compile().Invoke();

        }

    }

 

    private object GetInstanceWithInit(MemberInitExpression expression)

    {

        object instance = GetInstance(expression.NewExpression);

        foreach (MemberBinding binding in expression.Bindings)

        {

            ApplyBinding(instance, binding);

        }

        return instance;

    }

 

    private void ApplyBinding(object instance, MemberBinding binding)

    {           

        switch (binding.BindingType)

        {                   

            case MemberBindingType.Assignment:

                ApplyAssignmentBinding(instance, (MemberAssignment)binding);

                break;

            case MemberBindingType.ListBinding:

                ApplyListBinding(instance, (MemberListBinding)binding);

                break;

            case MemberBindingType.MemberBinding:

                ApplyMemberBinding(instance, (MemberMemberBinding)binding);

                break;

            default:

                throw new NotImplementedException();

        }

    }

 

    private void ApplyMemberBinding(object instance, MemberMemberBinding binding)

    {

        PropertyInfo property = (PropertyInfo)binding.Member;

        object memberValue = property.GetValue(instance, null);

        foreach (MemberBinding childBinding in binding.Bindings)

        {

            ApplyBinding(memberValue, childBinding);

        }

    }

 

    private void ApplyListBinding(object instance, MemberListBinding binding)

    {

        object list = ((PropertyInfo)binding.Member).GetValue(instance, null);

 

        foreach (ElementInit elementInit in binding.Initializers)

        {

            Delegate compiled = Expression.Lambda(Expression.NewArrayInit(typeof(object), elementInit.Arguments.ToArray())).Compile();

            object[] arguments = (object[])compiled.DynamicInvoke();

            elementInit.AddMethod.Invoke(list, arguments);

        }

    }

 

    private void ApplyAssignmentBinding(object instance, MemberAssignment assignment)

    {

        object value = EvaluateExpression(assignment.Expression);

 

        PropertyInfo info = (PropertyInfo)assignment.Member;

        info.SetValue(instance, value, null);

    }

 

    private object EvaluateExpression(Expression expression)

    {

        switch (expression.NodeType)

        {

            case ExpressionType.New:

                return GetInstance((NewExpression) expression);

            case ExpressionType.MemberInit:

                return GetInstanceWithInit((MemberInitExpression) expression);

            default:

                return Expression.Lambda(expression).Compile().DynamicInvoke();

        }

    }

 

    private object GetInstance(NewExpression expression)

    {

        return _serviceProvider.GetService(expression.Type);

    }

}


The only thing left is to then either provide an existing instance of IServiceProvider (i.e. the Windsor container) or creating an adaptor

public class DataDomainServiceProvider : IServiceProvider

{

    private readonly DataDomain _domain;

    private static readonly MethodInfo member = typeof(DataDomain).GetMethod("New");

 

    public DataDomainServiceProvider(DataDomain domain)

    {

        _domain = domain;

    }

 

    public object GetService(Type serviceType)

    {           

        return member.MakeGenericMethod(serviceType).Invoke(_domain, null);           

    }

}


There's a few things the enterprising mind can do with substitutions and member initialization I can think of, especially around IoC - anyone else have some ideas or thoughts on using/abusing them?

 |  | 
posted @ Wednesday, February 20, 2008 1:01:38 AM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | Trackback |
 Monday, February 04, 2008


So the sun has set on day 1 of the Summer Road Trip 2008 in Auckland - The Presentation was done by JB, Chris and Myself this afternoon - it went very well, people enjoyed the content and the mix of integration, server management, database and development topics really meshed together nicely I thought... 

There was enough to keep everyone interested, regardless of the hat you wear - and plenty of prizes too - well all love swag right?!

Big thanks to our MC Jaqcui, who handled the Intro and Outro and let everyone know about the local Ellerslie & Central Auckland user group's - where I'll be sure to run a few sessions later in the year... and of course Darryl for handling some of the finer details like the venue, lunch, and the dinner afterwards - much appreciated.

For all those that came along - first off thanks for coming, obviously without participation in these events they'll just dry up and stop happening - and second don't forgot that there is no time like the present to start picking up these technologies and developing applications with and for them - the products are all but ready, so why can't you be (and not only are they great technologies, they're fun too).

The next presentation is in Tauranga - and there are still places left, so sign up here - It's going to be on tomorrow (5th of Feb) at 1:00pm I believe.

And finally a short plug ;o)

SylviaParkArchitectureChat.JPG

For anyone that found this presentation interesting and would like to discuss the technical details of things like emerging technologies, general software Architecture, Developer Tools, Running software businesses etc.  I also organise the local Sylvia Park Architecture Chat - which is a pretty casual meeting of some very smart people in the .Net Community. 

We normally get together on a fortnightly basis at Garrisons in Sylvia Park and are always keen to have more people/fresh faces to come along and join in our discussions or even just float some development/architecture questions or problems you might have that the group can help solve - keep an eye on my blog, or the dot.net.nz mailing list for announcements of when we'll next be meeting up :)

And all are welcome of course!

posted @ Monday, February 04, 2008 8:24:40 AM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | Trackback |
 Wednesday, January 09, 2008
Update: 22nd May 2008 - Please if you have any .Net reactor related queries, post them to this google group, rather then emailing me directly, as you're more likely to get a response.  Cheers!

If you recall in the last Architecture Chat (#21) Gareth of Slyce Software mentioned the demise of .Net Reactor, a German code obfuscation product that many users swear by.. but over the past 2 or so months it went completely dark as the company ceased responding to any correspondence, or making releases - where as prior they were almost phenomenally fast to get back to queries, and we releasing every couple of weeks.

Well I got an interesting email from a .Net Reactor user who has been suffering the same issues, not having a response out the company in the last couple of months but he did advise that releases are starting to flow out the company again, with 3 new versions released in December... so things could be looking up, even if the wall of silence continues.

Apparently it got so bad that even some add-on vendors have withdrawn in-prorgess products due to a lack of communication with Eziriz - what I find interesting here is how quickly all the good work you can do building up a community around a product for developers can unwind - and demonstrates how important a visible "heartbeat" for a product is to keeping trust in your project - be it through regular releases, actively participating in forums and mailing lists or at the very least publishing the odd bit of news on your site.

Fingers crossed the company starts answering peoples emails again at any rate - it'd be a shame to see a popular product's community turn their back on it just because their worried it's going to dissappear completely.

Right, so yes, there is a point to this post - assuming the worst and .Net Reactor is winding down, can anyone else recommend an obfuscation/licensing products in the sub 300 US$ range that works well?

Edit:

Shortly after posting this I was notified that Apparently everything is good once more in .Net Reactor land with the lead developer having been taken away from development due to other life issues taking over in the later part of last year, but he's back and developing/communicating once more so it should be "business as usual".

I look forward to seeing what cool things Eziriz get up to in 2008!

Edit (Again):

And shortly after that I also got an email, so everything is definitely fine once more with .Net Reactor:
Dear Mr. Henderson, I am sorry for the problems you had with my product support. Gareth Hayter referred me to your blog. Please be sure, .NET Reactor product development/support is firing on all cylinders again.

Best regards,

Denis Mierzwiak, Chief Technical Officer.
posted @ Wednesday, January 09, 2008 6:17:54 AM (New Zealand Daylight Time, UTC+13:00)    Comments [2] | Trackback |
 Tuesday, December 11, 2007
So my last post was a quick look at Volta & WinForms (if you wonder why I was using WinForms rather then web, I just figured it'd be a good place to start, without the complications of what can/can not be translated to javascript) - I haven't really been keeping track of what other people are doing with Volta, but there have been a couple of posts from Microsoft bloggers, including Wes Dyer (on tier splitting a web application) and Drargos Manolescu (on tier splitting a winforms application) - hopefully some of the other members on the Volta team will pick up the gauntlet and start blogging shortly too.

This post is going to be very short (if you ignore the code snippets) - we've already seen how classes can be split into two, one being the client proxy the other the service implementation - but what happens if a class is used in the client and server but isn't fixed/pinned to run on a specific Tier via the RunAt attribute... that's the focus of this post.

So, in this example - I'm going to add a helper class to my previous example from the last post - which just formats some text all "pretty" like:

public class HelperClass

{

    public string PrettyFormat(string text)

    {

        return string.Format("--> {0} <--", text);

    }

}


Now I'll update my service to use pretty formatting:

[RunAt("Server")]

public class SomeService

{

    private readonly HelperClass _helper = new HelperClass();

 

    public string WelcomeMessage(string name)

    {

        return _helper.PrettyFormat(string.Format("Welcome: {0}", name));

    }

}


And lastly, I'll add an additional button called "welcomeLocalButton" which when clicked will make use of the helper to format some text on the client, instead of calling the WelcomeMessage method on the service.

public partial class Form1 : Form

{

    SomeService service = new SomeService();

    private HelperClass helper = new HelperClass();

 

    public Form1()

    {

        InitializeComponent();

    }

 

    private void welcomeButton_Click(object sender, EventArgs e)

    {  

        welcomeOutput.AppendText(service.WelcomeMessage(nameTextBox.Text));

    }

 

    private void welcomeLocalButton_Click(object sender, EventArgs e)

    {

        welcomeOutput.AppendText(helper.PrettyFormat("Welcome Local " + nameTextBox.Text));

    }

}


So this is how the app looks now...

6_welcome_local_winforms.png

Compile and run - everything works as expected, now looking at the generated client and server assemblies we see both contain... the same class - yep that's right it just duplicates the class in both the client and server tiers, without changing it at all.

Now for windows forms this doesn't appear as all that much of a miracle (it's still nice, we wouldn't want helper classes being turned into implicit services just because they're used across tiers)... but for web or other target platforms (such as embedded devices) this is where the elegance begins to kick in, not only are you able to declaratively specify where code is executing, but if you don't specify/fix (I wonder what the correct terminology is here?) a type to a specific tier you get the best of both worlds i.e. code that's native assemblies on the origin/server side and javascript implementations on the client side.

So to demonstrate the web equivalent I whipped up the following example - I was trying to think of something interesting that would be useful to do client and server-side - and thought, perhaps I would use Andrew's Inflector.Net - sadly there are a few issues with that, namely Regex isn't supported out of the box in Volta (which is a real shame, this is something I would've have expected to have been in the preview - regex being such a swiss army knife, especially for scripting) - so instead I picked something a little simpler - the Ordinalize functionality from Inflector, and just stripped out the other unrequired methods which would give us grief.

So the example is pretty simple, we have a web page that looks like this:

3_ordinalizer.png

You enter a number, it get's ordinalized, either via a remote call or a client-side call... so let's take a quick look at the code, first we have the ordinalize method:

public static class Inflector

{

    public static string Ordinalize(string number)

    {

        int n = int.Parse(number);

        int nMod100 = n % 100;

 

        if (nMod100 >= 11 && nMod100 <= 13)

        {

            return number + "th";

        }

 

        switch (n % 10)

        {

            case 1:

                return number + "st";

            case 2:

                return number + "nd";

            case 3:

                return number + "rd";

            default:

                return number + "th";

        }

    }

}


Then we have the server-side OrdinalizerService:

[RunAtOrigin]

public class OrdinalizerService

{

    public string Ordinalize(string number)

    {

        return Inflector.Ordinalize(number);

    }

 

    [Async]

    public extern void Ordinalize(string number, Callback<string> callback);

}


And finally we have the UI code:

public partial class VoltaPage1 : Page

{

    Input numberElement;

    Button button1;

    Div resultsElement;

    Button button2;

 

    public VoltaPage1()

    {

        InitializeComponent();

 

        var ordinalizer = new OrdinalizerService();

 

        button1.Click += delegate

        {

            var name = numberElement.Value;

            resultsElement.InnerText = Inflector.Ordinalize(numberElement.Value);

        };

 

        button2.Click += delegate

        {

            var name = numberElement.Value;

            ordinalizer.Ordinalize(

                name,

                message => { resultsElement.InnerText = "Remote: " + message; });

        };

    }

 

    partial void InitializeComponent()

    {

        numberElement = Document.GetById<Input>("Text1");

        resultsElement = Document.GetById<Div>("Results");

        button1 = Document.GetById<Button>("Button1");

        button2 = Document.GetById<Button>("Button2");

    }

}


So... what's left after the tier-split?

Well if you open up reflector and look at either the client or the server assembly - you will still see the same Inflector class i.e. just like the previous winforms example it just copies it to both tiers - and that's it... no magic at this point, because the process of transforming the class to javascript doesn't occur untill runtime.  Though obviously it does need to copy it because the client and service layer are entirely independent.

I could stop there - but I'm sure many people are curious as to just what the javascript looks like :)

So just to round this post out - we'll take a brief look at the generated javascript - so if you use a tool like firebug while loading a page developed with volta you will see alot of activity going on as individual types are loaded one by one from the server, like so...

4_loading_assemblies_js.PNG

There are pages and pages of these calls... though there are plans to reduce the number of round trips in the future (obviously a round trip per type is a pretty bad idea in a complex app) but you need to keep your eye on the prize... Volta is not competing with meticulously hand crafted MVC web-based solutions with little sprinkles of Ajax here and there... the benefits would come from employing it where the complexity and drudgery of client side scripting is overwhelming and large amounts of asynchronous messages are being exchanged between client and server... at least that's where I see a sweet spot... obviously there are plenty of other side-effects as well (ubiquitous refactoring springs to mind).

Now if you scroll down past all the standard (BCL) and volta related types you eventually find... no mention of the Inflector type.

No magic here though - just type a value into the textbox and click Ordinalize Local - and flick back to Firebug's console... and you will see a request being made for the Inflector type - types are lazy loaded - makes a lot of sense, when you might have types only required by a single UI element on the screen that the user never touches.

So here's the request for the inflector type:

5_inflector_js_request.PNG

Notice the two query string parameters a (assembly) and t (type) ... and now if we were to flick over to the response tab, we would see the javascript produced for that type (see below)

Notice it adds this type to the list of types in the assembly, maintaining the same symantecs between javascript and the .net framework - obviously the javascript is a little scary, especially considering all the existing variable names have been lost - but for all that it's quite readable:

var CurrentAssembly = Assemblies["VoltaWeb.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"];

 

CurrentAssembly.TypeDefs["VoltaWeb.Inflector"] = (function(){

 

    var Ret = {};

 

    var Assembly = CurrentAssembly;

 

    var asmRef_0 = Assembly.References.ref_0();

 

    var typDef_0 = GetTypeDef(asmRef_0, "System.Object");

 

    var typDef_1 = GetTypeDef(asmRef_0, "System.Object");

 

    var typRef_0 = GetTypeRef(asmRef_0, "System.String");

 

    var typRef_1 = GetTypeRef(Assembly, "VoltaWeb.Inflector");

 

    var typRef_2 = GetTypeRef(asmRef_0, "System.Object");

 

    var typRef_3 = GetTypeRef(asmRef_0, "System.Object");

 

    var typRef_4 = GetTypeRef(asmRef_0, "System.Boolean");

 

    var typRef_5 = GetTypeRef(asmRef_0, "System.Int32");

 

    var typRef_6 = GetTypeRef(asmRef_0, "System.Void");

 

    var methDef_0 = GetMethodDef(typDef_0, "ToString", [typRef_0]);

 

    var methDef_1 = GetMethodDef(typDef_1, "Equals", [typRef_2, typRef_4]);

 

    var methDef_2 = GetMethodDef(typDef_1, "GetHashCode", [typRef_5]);

 

    var methDef_3 = GetMethodDef(typDef_0, "Finalize", [typRef_6]);

 

    var methRef_0 = GetMethodRef(typRef_3, "ToString", [typRef_0]);

 

    var methRef_1 = GetMethodRef(typRef_3, "Equals", [typRef_2, typRef_4]);

 

    var methRef_2 = GetMethodRef(typRef_3, "GetHashCode", [typRef_5]);

 

    var methRef_3 = GetMethodRef(typRef_3, "Finalize", [typRef_6]);

 

    var Methods = {};
   
    Methods["meth_13"/*VoltaWeb.Inflector.Ordinalize*/] = function _VoltaWeb_Inflector_Ordinalize_System_String_(param_2) {

 

        var asmRef_0 = Assembly.References.ref_0();

 

        var typDef_0 = GetTypeDef(asmRef_0, "System.Int32");

 

        var typDef_1 = GetTypeDef(asmRef_0, "System.String");

 

        var typRef_0 = GetTypeRef(asmRef_0, "System.String");

 

        var typRef_1 = GetTypeRef(asmRef_0, "System.Int32");

 

        var methDef_0 = GetMethodDef(typDef_0, "Parse", [typRef_0, typRef_1]);

 

        var methDef_1 = GetMethodDef(typDef_1, "Concat", [typRef_0, typRef_0, typRef_0]);

 

        var loc_3 = typDef_0.Initializer({});

 

        var loc_4 = typDef_0.Initializer({});

 

        var loc_5 = typDef_0.Initializer({});

 

        var $next;

 

        $next = 0;

 

        while (true) switch($next) {

 

            case 0:

 

                {

 

                    loc_3 = methDef_0(param_2)/*System.Int32.Parse(System.String)*/;

 

                    loc_4 = loc_3 % 100;

 

                    var br1 = loc_4 < 11;

 

                    if (br1 || br1 === "") {

 

                        $next = 40;

 

                        continue;

 

                    }

 

                    var br2 = loc_4 > 13;

 

                    if (br2 || br2 === "") {

 

                        $next = 40;

 

                        continue;

 

                    }

 

                    return methDef_1(param_2, "th")/*System.String.Concat(System.String,System.String)*/;

 

                    $next = 40;

 

                }

 

            case 40:

 

                {

 

                    loc_5 = loc_3 % 10;

 

                    switch(loc_5 - 1){

 

                        case 0:

 

                            $next = 70;