Category Archives: Development

[Event] AgileMalta – 5th December 2008

I’m pleased to see AgileMalta running its second conference. I have a soft spot for Malta having essentially lived there on and off for many years. It has probably changed a lot, but I still like to think I know Malta and Gozo almost as well as I know the back of my hand. I can’t think of a better mix, the islands of Malta, Gozo and Comino, their people and an agile development conference…

What: Talks given by people who have had a hands-on experience with Agile with international clients. The Key Note speaker is Joakim Ohlrogge. Local speakers are two local persons who actively participate in Agile projects, Aldo Cauchi Savona and Dave Sammut.
Date: Friday, December 5th 2008
Location: Hilton Hotel, St. Julians
Duration: Half-day conference
Price: T.B.A.

Further details can be found here:
http://www.agilemalta.com/events/agile-conference-december-2008/

Overview:
Success in today’s software industry requires a process, an environment and people that are able to achieve business goals within tighter deadlines, without compromising quality or reducing employee moral. Your process needs to be able to be attractive to foreign investment, your employees need the skills to deliver and sustain the process.

Whether you are interested in Agile or seeing how you can improve your own development process, the AgileMalta Conference is a great opportunity for people at all levels to gather together to learn about and share experiences on Agile software development process.

In our first conference we provided talks and discussion sessions for people at all levels to come into contact and learn about Agile. In the upcoming conference we will build upon feedback from the 1st conference and from our website. We decided to provide you with talks on implementing Agile and dealing with common issues when using such a process.

Join the AgileMalta Facebook group here!

Technorati Tags: , , , , , ,

Open XML – Resources

This post serves as a placeholder for my Open XML links, resources, etc. I will update it from time to time.

History
04/11/2008 – I’ve updated the demo code to include the code used in my screencast demonstrating Word 2007 Content Controls.

03/11/2008 – I’ve updated the demo code to include examination of the customXML file that is populated by the content control example (ContentControl.docx). Demo 5 shows how we can inject our own XML into the content controls.

Demo 6 presents the few lines of code required to extract the XML (as populated by the content controls) into an XmlDocument. Once the customXML is in an XmlDocument we are free to access the nodes as required.

Thus we are now in a position were we can create a document with custom data present, pass it to a user, the user can amend the custom data, save the document and send it back to us. We can then extract that custom data for subsequent processing. I will prepare a short screencast to demonstrate this – watch this space.

28/10/2008 – Posted pre-VBUG Newcastle inaugural delivery of An Introduction to Open XML. Download the slides and Visual Studio 2008 / Open XML SDK 2 CTP1 demo code. It’s likely that I will update this code to reflect further CTP releases.

**

Eric White’s blog entry about the first CTP of the Open XML SDK V2.

Microsoft’s primary Open XML portal, OpenXMLDeveloper.org.
Microsoft’s on-line forum for Open XML

OpenXML Code Snippets (for Visual Studio 2005) (Managing code snippets)

Blogs
Brian Jones
Mauricio Ordonez
Doug Mahugh
Kevin Boske
Erika Ehrli
Gray Knowlton’s OpenXML content

Product/Technology Blogs
XPS
Word
Excel

Videos
Open XML File Formats

Using Word 2007 Content Controls
Matthew Scott: Application Development using the Open XML File Formats
Matthew provides an excellent explanation of Word 2007’s content controls and customXML parts. Before OpenXML you probably found yourself using Word bookmarks to leave placeholders inside a Word document – content controls essentially replace those.

Andrew Coates has some excellent information about using Content Controls in conjunction with Matthew’s Word Content Control Toolkit (available on CodePlex).

Technorati Tags: , , , , , , , , , ,

Implementing GetEmailAddressFromExchange in C#

As developers we often find ourselves writing small one off applications to perform a specific “here and now” requirement. The task was to produce a list of e-mail addresses from a Microsoft Outlook folder. I’m reasonably happy with my understanding of the Microsoft Outlook object model, well, happy enough that I’ve managed to get it to do what I need it to do. I am by no means an expert, however since I’ve been making reasonable progress with my “duplicate e-mail remover” application, I figured that iterating over an Outlook folder extracting the e-mail address on they way couldn’t be too hard.

Indeed, for SMTP e-mail addresses, it’s fairly straightforward – a mail message in Outlook has a SenderEmailAddress property that holds the e-mail address in the format name@domain.com.

In a corporate environment you may find X400 formatted addresses similar to this one:

/O=/OU=GLOBAL/CN=RECIPIENTS/CN=FBUTCHER76409312

The aforementioned SenderEmailAddress is also used to store this address, so if you were expecting an SMTP address, too bad!

However, mail messages also have a string property SenderEmailType which returns EX for mail items that use Exchange Server addressing. Here’s how you might use it:

               // Catch e-mails sitting on an Exchange Server...
                            if (oMsg.SenderEmailType == "EX")
                            {                                
                                display = GetEmailAddressFromExchange(oMsg.SenderName);
                            }
                            else
                                // Otherwise, assume SMTP addresses
                                display = string.Format("{0}", oMsg.SenderEmailAddress);

The eagle-eyed reader will have noticed the call to GetEmailAddressFromExchange. I really wanted an SMTP address for all the mail items in the folder(s) in question. A little bit of searching revealed this well-written article by Julian Biddle at An Original Idea.

Julian’s article explained how to get an e-mail address from an Exchange Server address using Visual Basic in .NET. I prefer to use C#, so set about converting Julian’s code (which was known to work). There are other flavours of this code floating on the Internet, this one works for me, your mileage may vary.

The entire application can be downloaded here. This little application is crude, but it solved a problem for me at the time of writing. It demonstrates how to iterate over Microsoft Outlook folders (not just the Inbox) building a treeview on the way. It also demonstrates how to save the contents of a ListView control to a CSV file.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Office.Interop.Outlook;
using System.Runtime.InteropServices;
using System.IO;

namespace OutlookEmailAddressExtractor
{
    public partial class frmExtractEmailAddresses : Form
    {
        public frmExtractEmailAddresses()
        {
            InitializeComponent();
        }

        const int S_OK = 0;

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi, EntryPoint = "HrGetOneProp@12")]
        private static extern void HrGetOneProp(IntPtr pmp, uint ulPropTag, out IntPtr ppProp);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi, EntryPoint = "HrSetOneProp@8")]
        private static extern void HrSetOneProp(IntPtr pmp, IntPtr pprop);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi, EntryPoint = "MAPIFreeBuffer@4")]
        private static extern void MAPIFreeBuffer(IntPtr lpBuffer);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        private static extern int MAPIInitialize(IntPtr lpMapiInit);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        private static extern void MAPIUninitialize();

        const string IID_IMAPIProp = "00020303-0000-0000-C000-000000000046";
        const uint PR_SMTP_ADDRESS = 972947486;

        struct SPropValue
        {
            public uint ulPropTag;
            public uint dwAlignedPad;
            public long Value;
        }

        Microsoft.Office.Interop.Outlook.Application oApp;
        NameSpace oNS;


        private string GetEmailAddressFromExchange(string emailName)
        {
            MailItem loDummyMsg = (MailItem)oApp.CreateItem(OlItemType.olMailItem);
            Recipient loAddress = loDummyMsg.Recipients.Add(emailName);
            loAddress.Resolve();
            string SMTPAddress = GetMAPIProperty(loAddress.AddressEntry.MAPIOBJECT, PR_SMTP_ADDRESS);

            return SMTPAddress;
        }


        private string GetMAPIProperty(object oMAPIObject, uint uiPropertyTag)
        {
            if (oMAPIObject == null)
            {
                return "";
            }

            string sProperty = "";
            IntPtr pPropValue = IntPtr.Zero;

            IntPtr IUnknown = IntPtr.Zero;
            IntPtr IMAPIProperty = IntPtr.Zero;

            try
            {
                MAPIInitialize(IntPtr.Zero);

                IUnknown = Marshal.GetIUnknownForObject(oMAPIObject);

                Guid guidMAPIProp = new Guid(IID_IMAPIProp);

                if (Marshal.QueryInterface(IUnknown, ref guidMAPIProp, out IMAPIProperty) != S_OK)
                {
                    return "";
                }

                try
                {
                    HrGetOneProp(IMAPIProperty, uiPropertyTag, out pPropValue);

                    if (pPropValue == IntPtr.Zero)
                    {
                        return "";
                    }

                    SPropValue propValue = (SPropValue)Marshal.PtrToStructure(pPropValue, typeof(SPropValue));

                    sProperty = Marshal.PtrToStringAnsi(new IntPtr(propValue.Value));
                }
                catch (System.Exception ex)
                {
                    throw ex;
                }
            }
            finally
            {
                if (pPropValue != IntPtr.Zero)
                {
                    MAPIFreeBuffer(pPropValue);
                }

                if (IMAPIProperty != IntPtr.Zero)
                {
                    Marshal.Release(IMAPIProperty);
                }

                if (IUnknown != IntPtr.Zero)
                {
                    Marshal.Release(IUnknown);
                }

                MAPIUninitialize();
            }

            return sProperty;
        }

        

        void _PopulateFolderList(MAPIFolder oFolder, TreeNode node)
        {
            foreach (MAPIFolder folder in oFolder.Folders)
            {
                string s =String.Format("{0} ({1}) [{2}]", 
                                        folder.Name, 
                                        folder.Folders.Count, 
                                        folder.Items.Count);
                
                TreeNode thisNode = node.Nodes.Add(s);

                thisNode.Tag = folder;

                if (folder.Folders.Count > 0)
                {
                    _PopulateFolderList(folder, thisNode);
                }
            }
        }

        private void btnGetFolders_Click(object sender, EventArgs e)
        {
            oApp = new Microsoft.Office.Interop.Outlook.Application();
            oNS = oApp.GetNamespace("MAPI");

            progressBar.Minimum = 0;
            progressBar.Maximum = oNS.Folders.Count;
            progressBar.Value = 0;

            this.Cursor = Cursors.WaitCursor;

            foreach (MAPIFolder f in oNS.Folders)
            {
                TreeNode node = tvOutlookFolders.Nodes.Add(f.Name);

                if (f.Name != "Public Folders" && f.Name != "Internet Calendars")
                    _PopulateFolderList(f, node);

                progressBar.Value++;
            }

            progressBar.Value = 0;
            this.Cursor = Cursors.Arrow;
        }


         

        private void btnGetEmailAddresses_Click(object sender, EventArgs e)
        {
            TreeNode nodeSelected = tvOutlookFolders.SelectedNode;
            MAPIFolder folder = (MAPIFolder)nodeSelected.Tag;

            this.Cursor = Cursors.WaitCursor;

            lvEMailInSelectedFolder.Items.Clear();

            if (folder != null)
            {
                progressBar.Maximum = folder.Items.Count;
                progressBar.Minimum = 0;
                progressBar.Value = 0;

                string sClassComp = "IPM.Note";

                Items oItems = folder.Items;

                label1.Text = oItems.Count.ToString();

                MailItem oMsg = (MailItem)oItems.GetFirst();

                while (oMsg != null)
                {
                    if (oMsg.MessageClass == sClassComp)
                    {

                        if (oMsg.Body != null)
                        {
                            string display;

                            // Catch e-mails sitting on an Exchange Server...
                            if (oMsg.SenderEmailType == "EX")
                            {                                
                                display = GetEmailAddressFromExchange(oMsg.SenderName);
                            }
                            else
                                // Otherwise, assume SMTP addresses
                                display = string.Format("{0}", oMsg.SenderEmailAddress);

                            bool okToAdd = true;
                                
                            if (cbIgnoreDuplicates.Checked)
                                okToAdd = lvEMailInSelectedFolder.FindItemWithText(display) == null;

                            if (okToAdd)
                            {
                                ListViewItem item;
                                item = lvEMailInSelectedFolder.Items.Add(display);

                                item.SubItems.Add(oMsg.SenderName.ToString());

                                if (oMsg.Subject != null)
                                    item.SubItems.Add(oMsg.Subject.ToString());
                                else
                                    item.SubItems.Add(" ");

                                item.SubItems.Add(oMsg.SenderEmailType);
                            }
                        }
                    }

                    bool exceptionRaised = true;

                    while (exceptionRaised)
                    {
                        try
                        {
                            oMsg = (MailItem)oItems.GetNext();
                            progressBar.Value++;
                            exceptionRaised = false;
                        }
                        catch
                        {
                            exceptionRaised = true;
                        }
                    }
                }

                lvEMailInSelectedFolder.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);

                btnSaveToCSV.Enabled = true;

                progressBar.Value = 0;

                this.Cursor = Cursors.Arrow;
            }
        }

        private void btnSaveToCSV_Click(object sender, EventArgs e)
        {
            StringBuilder listViewContent = new StringBuilder();

            foreach (ListViewItem item in this.lvEMailInSelectedFolder.Items)
            {
                listViewContent.Append("\"");
                listViewContent.Append(item.Text);
                listViewContent.Append("\"");

                listViewContent.Append(",");

                listViewContent.Append("\"");
                listViewContent.Append(item.SubItems[1].Text);
                listViewContent.Append("\"");
               
                listViewContent.Append(Environment.NewLine);
            }

            saveFileDialog.FileName = "e-mail addresses.csv";
            saveFileDialog.Filter = "CSV files (*.csv)|*.csv|All files (*.*)|*.*";
            saveFileDialog.ShowDialog();

            if (saveFileDialog.FileName != "")
            {
                TextWriter tw = new StreamWriter(saveFileDialog.FileName);

                tw.WriteLine(listViewContent.ToString());

                tw.Close();
            }
        }

        private void tvOutlookFolders_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (tvOutlookFolders.SelectedNode != null)
            {
                btnGetEmailAddresses.Enabled = true;
            }
        }
    }
}

Technorati Tags: , , , , , , , , , , , ,

The importance of calling .Close()

Courtesy of Andrew Westgarth, via IM, I found myself look at Visual Basic code last week. Andrew’s “designer” was having problems editing some files that made up an application that Andrew was developing…seemed that something was keeping a lock on the files such that they couldn’t be edited. I suggested a couple of things, including hard-coding the filename (avoiding use of Server.MapPath) just to see what happened.

However, after a little experimentation, it turns out that the XmlReader instance wasn’t being closed and as such was keeping a lock on the XSL/T file in question. The solution was to call the .Close() method. It’s obvious now, however sometimes whilst in thick of it, it’s very easy forget to call such methods, nobody’s perfect.

Andrew provides a full write-up over here:

***warning contains VisualBasic code***
Can’t Save your XSL/T File? Have You Closed Your XMLReader?/a>

Technorati Tags: , , , ,

Ugh. Memes. How I Got Started In Software Development.

Thanks to Colin (Stuff that’s in my head) and Barry (idunno.org) for tagging me in this meme.  I’m only promoting it because it gives me a chance to document a little bit of my past…

How old were you when you started programming?
I suppose I was about 12, probably tinkering with a TRS-80 (in Tandy/RadioShack), an Acorn Electron, a ZX-81 and an Oric 1.

However it wasn’t until I was 14 when a BBC Micro (Model B) arrived complete with it’s User Guide.  Those where the days when user guides were real user guides and …  The User Guide itself was over an inch thick and was ring bound.  The ring binding was perfect, you could lay it flat on a table and it would stay open, great for typing whilst reading.  This is in complete contrast to the RISC OS 3 Programmer’s Reference Manuals that accompanied the Acorn Archimedes (more about this shortly).  I learned everything there was to learn about the BBC, in some cases this meant getting very intimate with SHIELA, JIM and FRED – sometimes all at the same time (user guide page 421)!

Those were also the days of cassette-based storage.  How slow were they?  Very slow.  Indeed, when I finally got a 5.25” disk drive, I spent a lot of time moving tape-based programs on to disk.  Of course, some tape-based programs where fussy and insisted that they load and run from “PAGE &0E00”, whereas the disk control moved the base page to &1900.  So I spent more time working out how to load programs into a different PAGE then magically move it to where it expected to be where it could then be executed from.  The process of moving tape-based programs onto disk was something I became pretty good at.

How did you get started in programming?
I guess that I have my father to thank for this!  When we were in Libya, he brought home fan-fold listing paper for me to use as scrap paper.  Whilst a lot of it was ‘address listings’ and other such program output, some of it contained COBOL listings. 

What was your first language?
That would be BBC Basic.  I can’t remember how long it took me to master it.  BBC Basic had the advantage of a built in assembler – anything that was a little bit slow in interpreted Basic could be hand-cranked using 6502 Assembler.  They were the days – it was possible to learn how to understand the entire computer: it’s architecture, it’s hardware, it’s interfaces, you name it.

What was the first real program that you wrote?
I don’t know if I can remember the very first program that I wrote.  I can remember writing a number of programs whilst at school.  There was a network broadcast program that I called Channel 5 – obviously long before the TV station came along.  Then there was my A-Level project, a program that created graphs – it had to manage data, graph plotting and printing: a tall order in those days.

Part of the graphing program involved sorting data.  After the graph data had been loaded from file, I was using arrays to hold the data in memory.  My sort routine involved looking at the first element of the array, then comparing its value with the second element – if the first was less than the second, I’d use a temporary variable to allow me to swap the array elements.  I was, as you might imagine, very pleased with myself – this was a really cool sorting method!   Of course, like many/all first-time programmers, I believed that I was the first person to “invent” this sorting technique.  Oh how much I had to learn – it didn’t take long for the bubble [sic] to burst!

What languages have you used since you started programming?
ARM Assembly Language, Turbo C, Turbo C++, Turbo Pascal, ML, Perl, COBOL, Borland Pascal, Delphi, Visual Basic 6, Classic ASP (VB), PHP, Visual Basic (.net), C#.

What Was Your First Programming Gig?
Gig? I suppose by this it means where I was actually paid to write code.  That would have been in 1990 when I spent a year working for IBM in Hursley, near Winchester.  At the time I was an avid Turbo Pascal fan – my first boss was a Modula-2 dev-head, he loved it.  I inherited a C language parser written in Modula-2.  It was fun working on the parser…until I discovered that the recursive nature of the parsing process wasn’t controlled using local variables as it should be, but was controlled using global variables.  I think this was close to my first “OMG, I don’t believe it” moments (I’ve had plenty more of those since then!)

If you knew then what you know now would you have started programming?
I think the short answer to this question would be yes, yes I would have started programming.  However would I have chosen to learn assembler language?  In today’s abstract world, with class libraries getting evermore feature rich, it seems that fewer folks truly understand today’s processors at an instruction set level.  I wonder if there will be a shortage of assembly language developers in years to come? 

If there is one thing you learned along the way that you would tell new developers what would that be?
Keep it clean, keep your code clean.  It’s difficult to teach “feeling” – when I’m writing code I often know very early on that I’m probably writing code that will be difficult to maintain – it’s at that point I stop and think about better (read: simpler) ways of achieving the same thing.  In the same thought, I’d also recommend that you shouldn’t try and write perfect code the first time.  Don’t be afraid to write code with refactoring in mind – there are plenty of good tools that will help get there!

What’s the most fun you’ve ever had … programming?
You might think I’m weird (or may be wired) however this is an honest answer!  Back in about 1994 I was working in Newcastle as part of an Acorn Archimedes library development team.  One of the application developers was about to go on holiday, he had been frantically getting his CD-ROM based application ready for production.  Disaster struck, somehow he managed to delete his source directory (yes, backups, yada yada, I know…)  Rather than let him cancel his holiday, I hauled his Acorn A5000 into my office space (thus I had two A5000s) and proceeded to recover as much of the source code as I could.  I couldn’t get it all back, so in the two weeks that he was away, I filled in the blanks.

References
http://en.wikipedia.org/wiki/ARM_architecture

http://acorn.chriswhy.co.uk/Computers/A300.html

Tag, you’re next: Richard Peat, David Christiansen, Ian Smith, Scott Lovegrove, Danny Thorpe

Implementing Excel’s STDDEVP in C#

I have been adding functionality to one of my applications. Without going into huge amounts of detail, it’s a C# application that pushes data out to Microsoft Excel – end users like Excel! The functionality that I’m adding was prototyped inside Microsoft Excel using simulated data and…the Excel Analysis Toolpak. To cut a long story short, I really wanted to remove the reliance on the Toolpak. In fact, I really wanted as much of the control element pulled back into the C# application, i.e. I wanted Excel doing more presentation of data and less scripting.

Part of that functionality involved replicating a few of Excel’s statistical functions, most notably STDDEVP (more details here)

Of course, it’s very likely that there’s a .NET implementation available in the .NET Framework…however my brief search was inconclusive, so I set about writing my own. The code you see below will compile and run using Visual Studio 2005. If you are using Visual Studio 2008 you can take advantage of the built in Sum, Average and Count methods (e.g. total = n.Sum(); instead of the foreach…total+=num loop)

[C#, compiled and tested using Visual Studio 2005]

class Program
{
    static public double STDDEVP(params double[] n)
    {
        double total = 0, average = 0;

        foreach (double num in n)
        {
            total += num;     
        }
  
        average = total / n.Length;
        
        double runningTotal = 0;

        foreach (double num in n)
        {
            runningTotal += ((num - average) * (num - average));
        }

        double calc = runningTotal / n.Length;
        double standardDeviationP = Math.Sqrt(calc);

        return standardDeviationP;
    }

    static void Main(string[] args)
    {
        double s = STDDEVP(1, 2, 3, 4, 5, 6, 7);
        Console.WriteLine(s);
        Console.ReadLine();
    }
}

This worked for me – your mileage may vary.

Technorati Tags: , , ,

UK Heroes Happen Here Microsoft Launch

Heroes Happen Here

I was able to attend the big Heroes Happen Here product launch last week.

Andy Westgarth and myself recorded a few interviews with the Microsoft Executives, expect to see those over appearing soon. DC was kind enough to take on the cameraman role – thanks! In the meantime, I have some photographs that demonstrate the crowds, the socialisation and the chinposin that was happening!

For all the good stuff surrounding speakers and how you can watch the sessions again (or for the first time if you didn’t make to the show), Daniel was kind enough to write this succinct piece!

Technorati Tags: , , ,

Irish Microsoft Technology Conference : 2-4 April 2008

What:
The IMTC 2008, is an 8 track, 40 session extravaganza covering a breadth of Microsoft’s latest emerging technologies. Throughout the festival there will be numerous networking opportunities, coffee and session re-runs.

Now in its third year, the IMTC 2008 is the second of seven major technology conferences in IrishDev.coms IxTC Series 2008. Co-organised with the Irish Microsoft Technology User Group and First Port Jobs, it’s an event by the Irish technology community for the Irish technology community.

The IMTC 2008 is being run over one evening and two action packed days – this is yet another Irish tech conference you cannot afford to miss!

When:
Begins 7.00pm Wednesday 2nd April with Keynotes, 40 technology sessions on Thursday and Friday 3rd and 4th, concluding with post conference drinks.

It’s not free, but at €189 for two days and an evening of technical content, it’s excellent value!

I’ll be speaking at this event – Test-Driven Development and Code Coverage using Visual Studio 2008 Professional.

Further information:
http://imtc.firstport.ie/

Technorati Tags: , , , , , , , , , ,

[Ireland, Dublin] Event – Irish Microsoft Technology Conference 2008

What:
The IMTC 2008, is an 8 track, 40 session extravaganza covering a breadth of Microsoft’s latest emerging technologies. Throughout the festival there will be numerous networking opportunities, coffee and session re-runs.

Now in its third year, the IMTC 2008 is the second of seven major technology conferences in IrishDev.coms IxTC Series 2008. Co-organised with the Irish Microsoft Technology User Group and First Port Jobs, it’s an event by the Irish technology community for the Irish technology community.

The IMTC 2008 is being run over one evening and two action packed days – this is yet another Irish tech conference you cannot afford to miss!

When:
Begins 7.00pm Wednesday 2nd April with Keynotes, 40 technology sessions on Thursday and Friday 3rd and 4th, concluding with post conference drinks.

It’s not free, but at €189 for two days and an evening of technical content, it’s excellent value!

I’ll be speaking at this event – Test-Driven Development and Code Coverage using Visual Studio 2008 Professional.

Further information:
http://imtc.firstport.ie/

Technorati Tags: , , , , , , , , , ,

[UK, Cambridge] Event – Code Generation – 25-27 June

Code generation is getting more and more press, more so since the widespread adoption of the Microsoft .NET Framework. It seems fitting that such an important topic gets its own conference time.

Code Generation 2008

It’s not free, however it is very reasonably priced. At the time of writing you could attend the whole conference using an Early Bird Rate – All Days (£475 + VAT) [Early Bird Rate]

Technorati Tags: ,