Using the Microsoft Charting Library from F#

November 3rd, 2008 matt Posted in Programming 2 Comments »

Since Microsoft released the charting controls used in SQL Server 2008 reporting as a standalone product, I decided to try them out from F#.

This makes a lot of sense because F# allows you to write scripts and run them from within Visual Studio in F# Interactive mode.  I love it because it’s the flexibility of MATLAB scripting (just try new things out without compiling) with the power and speed of the .NET Framework (MATLAB is based on layers and layers of Java and is by no means fast…).

To use the charting library from F#, the first thing we need is a form with a single chart control docked in it.  This is relatively simple, though I’ve copy/pasted/modified a lot of the visual designer code from one of the demo projects, so it looks like a lot, but it’s not.

type ChartForm =

    inherit Form

    val private chart1 : Chart

    val private legend1 : Legend

    val private series1 : Series

    val private title1 : Title

    val private chartArea1 : ChartArea

    new() as this =

        { chart1 = new Chart()

          legend1 = new Legend()

          series1 = new Series()

          title1 = new Title()

          chartArea1 = new ChartArea() } then

            this.chart1.BeginInit()

            this.SuspendLayout()

            //

            // chart1

            //

            this.chart1.BackColor <- System.Drawing.Color.WhiteSmoke;

            this.chart1.BackGradientStyle <- System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom;

            this.chart1.BackSecondaryColor <- System.Drawing.Color.White;

            this.chart1.BorderlineColor <- System.Drawing.Color.FromArgb(((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));

            this.chart1.BorderlineDashStyle <- System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;

            this.chart1.BorderlineWidth <- 2;

            this.chart1.BorderSkin.SkinStyle <- System.Windows.Forms.DataVisualization.Charting.BorderSkinStyle.Emboss;

            this.chart1.Dock <- DockStyle.Fill

            this.chartArea1.Area3DStyle.Inclination <- 15;

            this.chartArea1.Area3DStyle.IsClustered <- true;

            this.chartArea1.Area3DStyle.IsRightAngleAxes <- false;

            this.chartArea1.Area3DStyle.Perspective <- 10;

            this.chartArea1.Area3DStyle.Rotation <- 10;

            this.chartArea1.Area3DStyle.WallWidth <- 0;

            // Should be using Enum.combine…

            this.chartArea1.AxisX.LabelAutoFitStyle <- System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles.IncreaseFont + System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles.DecreaseFont + System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles.WordWrap

            this.chartArea1.AxisX.LabelStyle.Font <- new System.Drawing.Font(“Trebuchet MS”, 8.25F, System.Drawing.FontStyle.Bold);

            this.chartArea1.AxisX.LineColor <- System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));

            this.chartArea1.AxisX.MajorGrid.LineColor <- System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));

            this.chartArea1.AxisX.ScrollBar.LineColor <- System.Drawing.Color.Black;

            this.chartArea1.AxisX.ScrollBar.Size <- 10.0;

            this.chartArea1.AxisY.LabelStyle.Font <- new System.Drawing.Font(“Trebuchet MS”, 8.25F, System.Drawing.FontStyle.Bold);

            this.chartArea1.AxisY.LineColor <- System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));

            this.chartArea1.AxisY.MajorGrid.LineColor <- System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));

            this.chartArea1.AxisY.ScrollBar.LineColor <- System.Drawing.Color.Black;

            this.chartArea1.AxisY.ScrollBar.Size <- 10.0;

            this.chartArea1.BackColor <- System.Drawing.Color.Gainsboro;

            this.chartArea1.BackGradientStyle <- System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom;

            this.chartArea1.BackSecondaryColor <- System.Drawing.Color.White;

            this.chartArea1.BorderColor <- System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));

            this.chartArea1.BorderDashStyle <- System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;

            this.chartArea1.CursorX.IsUserEnabled <- true;

            this.chartArea1.CursorX.IsUserSelectionEnabled <- true;

            this.chartArea1.CursorY.IsUserEnabled <- true;

            this.chartArea1.CursorY.IsUserSelectionEnabled <- true;

            this.chartArea1.Name <- “Default”;

            this.chartArea1.ShadowColor <- System.Drawing.Color.Transparent;

            this.chart1.ChartAreas.Add(this.chartArea1);

            this.legend1.BackColor <- System.Drawing.Color.Transparent;

            this.legend1.Enabled <- false;

            this.legend1.Font <- new System.Drawing.Font(“Trebuchet MS”, 8.25F, System.Drawing.FontStyle.Bold);

            this.legend1.IsTextAutoFit <- false;

            this.legend1.Name <- “Default”;

            this.chart1.Legends.Add(this.legend1);

            this.chart1.Location <- new System.Drawing.Point(16, 58);

            this.chart1.Name <- “chart1″;

            this.series1.BorderColor <- System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));

            this.series1.ChartArea <- “Default”;

            this.series1.ChartType <- System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;

            this.series1.Legend <- “Default”;

            this.series1.Name <- “Series1″;

            this.series1.ShadowColor <- System.Drawing.Color.Black;

            this.chart1.Series.Add(this.series1);

            this.chart1.Size <- new System.Drawing.Size(412, 296);

            this.chart1.TabIndex <- 0;

            this.title1.Font <- new System.Drawing.Font(“Trebuchet MS”, 12.0f, System.Drawing.FontStyle.Bold);

            this.title1.ForeColor <- System.Drawing.Color.FromArgb(((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));

            this.title1.Name <- “Title1″;

            this.title1.ShadowColor <- System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));

            this.title1.ShadowOffset <- 3;

            this.title1.Text <- “Two series with 20000 points each”;

            this.chart1.Titles.Add(this.title1);

            //

            // ChartForm

            //

            this.BackColor <- System.Drawing.Color.White;

            this.Controls.Add(this.chart1);

            this.Font <- new System.Drawing.Font(“Verdana”, 9.0f, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

            this.Name <- “ChartForm”

            this.chart1.EndInit()

            this.ResumeLayout(false)

    member this.Chart = this.chart1

    member this.Legend = this.legend1

    member this.Title = this.title1

    member this.ChartArea = this.chartArea1

At the end, I also expose the internal Chart, Legend, Title, and ChartArea objects.

With that out of the way, we need a few helper methods:

// Create a list of linearly-spaced numbers from start to stop that is count long

let linspace (start:float) (stop:float) (count:int) =

    [0..count]

    |> List.map (fun x -> ((stop-start)/(float count))*(float x)+start)

 

// Populate the series with the x- and y- values

let populateSeries (series:Series) (xList : float list) (yList : float list) =

    List.iter2 (fun (x:float) (y:float) -> series.Points.AddXY(x,y) |> ignore ) xList yList

The first method, linspace, just creates a uniformly-spaced list of floating point values from start to stop.  MATLAB users recognize linspace without a doubt.

The populateSeries method takes equal-length lists xList and yList and goes through each pair and adds those points to the specified series.

With those out of the way, we can go to town!

// Create our chart form

let testChart =

    let f = new ChartForm()

    f.Text <- “Charting Demo”

    f.Size <- new System.Drawing.Size(400, 250)

    f.Title.Text <- “Sine Waves”

    f

 

// Set up the series options

let sineSeries = testChart.Chart.Series.["Series1"]

sineSeries.ChartType <- SeriesChartType.FastLine

 

// x range is [0,10] with 100 numbers

let xValues = linspace 0.0 10.0 100

// plot y=2sin(x)+4sin(2x)

let yValues = xValues |> List.map (fun x -> 2.0*sin(x) + 4.0*sin(2.0*x))

 

// Populate the series

populateSeries sineSeries xValues yValues

 

// Show the chart

showForm testChart

Wow, that was pretty painless. We start by creating a ChartForm and setting a few properties like the title and size, set up the series display options, and then set up our x- and y-values of numbers according to the function y=2sin(x)+4sin(2x).  Then we populate the series with the values and show the form. You can’t get much simpler than that. I’ve reused the showForm method from my previous post.

Here’s the result:

image

Slick, eh? :)

AddThis Social Bookmark Button

F# Tip: Show a Form In Both Compiled and Interactive Mode

November 3rd, 2008 matt Posted in Programming 1 Comment »

Lately I’ve FINALLY been getting back into some F# after a brief hiatus.  I love the way that it keeps stretching my brain.  Things have changed quite a bit with all of the slick new usability enhancements in the latest CTP. I need to dig out my data analysis scripts from the beginning of the year.

One of the first things I tried to make when I was learning F# was a simple “Hello World” Windows Forms application.  Quickly you run into a problem — if you want to take advantage of the awesome “F# Interactive” window at the bottom of the screen, then after you have a form, you call .Show().  However, if you want the form to come up when the compiled application is executed, then you need to use Application.Run().  If we try to use Application.Run from within F# Interactive, we get the following error:

> let mainForm = new Form(Text=“Hello World”);;

 

val mainForm : Form

 

> Application.Run(mainForm);;

System.InvalidOperationException: Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.

   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)

   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)

   at System.Windows.Forms.Application.Run(Form mainForm)

   at <StartupCode$FSI_0024>.$FSI_0024._main()

stopped due to error

Hmmm, we need a way to distinguish whether we are in compiled or interactive mode.

Thankfully the F# team has defined a number of compiler flags named COMPILED and INTERACTIVE that we can use.  So we can have conditional code depending on the execution mode:

let showForm (f:Form) =

#if INTERACTIVE

    f.Show()

#endif

#if COMPILED

    Application.Run(f)

#endif

This works out well, since we can now just call showForm and not worry about what mode we’re in.  For example, this uber-simple Hello World WinForms application can be written as:

#light

 

open System.Windows.Forms;;

 

let showForm (f:Form) =

#if INTERACTIVE

    f.Show()

#endif

#if COMPILED

    Application.Run(f)

#endif 

 

let makeNewForm title =

    let f = new Form()

    f.Text <- title

    f

 

let mainForm = makeNewForm “Hello World”

showForm mainForm

 

// Or:

//”Hello World” |> makeNewForm |> showForm

Then, to run it in F# Interactive, just hit Ctrl-A (select all) and Alt-Enter (run selection in the F# Interactive Window).  Bam! Similarly, to run it in compiled mode we just punch F5.

Hope that helps! :) This won’t be the last F# post, trust me.

AddThis Social Bookmark Button

Microsoft Chart Controls Released

November 3rd, 2008 matt Posted in Programming 1 Comment »

Doing any kind of graph charting or data visualization in managed code has always required either expensive 3rd-party software (e.g. Dundas, etc) or feature-incomplete open source projects (ZedGraph and NPlot come to mind). Furthermore, doing COM interop with Excel charts can be a nightmare.

Many times I just want to plot a bunch of data, probably an X-Y plot, to see a trend in some blob of numbers I have laying around.  Being an engineer, most of the time I’ll reach for MATLAB, but lately I’ve been doing quite a bit of XML processing that (to say it nicely) is not at all well-suited for MATLAB. I wanted to stay on the .NET Framework, take advantage of the .NET libraries I’ve written to parse the files (Linq to XML anyone?) and plot the data.  I’ve used ZedGraph in the past as a managed charting library, but it can be quirky.

I just discovered yesterday that Microsoft has released Microsoft Chart Controls for Microsoft .NET Framework 3.5.  Whoa, really? Could this be a better solution to ZedGraph? They even have samples available for download. I decided to try it out.

I ran the installer (MSChart.exe) and found that the assemblies get installed to “C:\Program Files\Microsoft Chart Controls\Assemblies”. There are 4 dlls, 2 for WinForms and 2 for ASP.NET:

  • System.Web.DataVisualization.Design.dll
  • System.Web.DataVisualization.dll
  • System.Windows.Forms.DataVisualization.Design.dll
  • System.Windows.Forms.DataVisualization.dll

After installing the controls, I unzipped the samples and opened up WinFormsChartSamples.exe:

image

Wow, that doesn’t look familiar at all. :)   I could swear I’ve seen controls like that before….oh yeah, Dundas!  After a bit of poking around, it appears that Microsoft (specifically the SQL Server 2008 team) has acquired the data visualization bits from Dundas.  Cool. I’m glad that Microsoft released the stand-alone assemblies for charting so that I don’t have to install SQL Server 2008 just to get 2MB of DLLs :P

The charting controls are extremely customizable. Take a look at some of the samples:

image image
image image
image image

Very cool.  I’ll probably give them a test drive here soon.

Hope that helps! :)

AddThis Social Bookmark Button

Getting Started with Subversion – VisualSVN and TortoiseSVN

November 3rd, 2008 matt Posted in Programming 6 Comments »

Recently a couple friends have asked me how to get started using Subversion to manage their files, so here’s a step-by-step guide to get everything up and running.

Why use Subversion?

Subversion lets you:

  • Keep track of every version of a file stored in multiple locations (e.g. desktop, laptop, work machine, etc)
  • Synchronize these files so that no changes are lost, no matter which machine the file is last edited on
  • Collaborate with other people using the same set of files without losing changes no matter who is editing the files

During undergrad, I always dreaded group projects because everything typically involved the “divide and conquer” methodology.  My group members and I would divide up the work and then get together later and combine all of our work.  In theory this works great, but in practice, it becomes a major hassle, especially if multiple iterations are involved, because inevitably someone’s work would accidentally get erased or lost.

It wasn’t until I reached grad school (and learned how to use Subversion effectively) that things changed.  I had the opportunity to work on a number of group projects (like group papers and presentations) where all members used Subversion to coordinate the files.  The final crunch time was much more sane since all changes to the files from all group members could be tracked and merged seamlessly. It really was a night and day difference.

Subversion Architecture

To use Subversion, each “set of files” is called a “repository”.  A centralized “Subversion server” must be used, and may contain any number of file repositories. To access these files, any number of “Subversion clients” may be used, typically from different machines.  Since Subversion is open-source, a considerable amount of effort has been dedicated to making the system cross-platform.  In general a Subversion server may be set up on Linux, Windows, or Mac OSX, and Subversion clients exist similarly for Linux, Windows, and Mac.

image

When files are retrieved from the server to the client, it is called an “update”, and when new versions of the files are sent to the server from the client, it is called a “commit”.

A typical repository will go through a continuous cycle of update-edit-commit.

image

In this guide, I’ll explain how to set up both a server and client on Windows.  In my experience, the most user-friendly choice is VisualSVN as the Subversion server and TortoiseSVN as the Subversion client.

Install VisualSVN Server

  • Go to the VisualSVN Server homepage
  • Click on “download now
  • Download the latest version (1.6.1 at the time of this writing).  You should have received VisualSVN-Server-1.6.1.msi
  • Execute the installer after it has finished downloading
  • Accept the license agreement
  • In the next screen, leave the default values:
    image
  • This will set up a directory C:\Repositories\, where each subdirectory here will be the root directory for that particular file repository.   VisualSVN Server will let you set different permissions on each repository (and subdirectories in each repository, but that’s more advanced.) 
  • You’ll also want to use Subversion authentication (password hashes stored by VisualSVN Server) instead of Windows authentication (VisualSVN integrates with the existing Active Directory domain, if present — this is quite advanced as well.)
  • Then just click Install.
  • This will bring you to the main VisualSVN Sever management console:
    image
  • Notice that there are no repositories, no users, and no groups (yet) :)

Create Users

  • First we’ll need to create a user that has permission to access the repositories (which ones we’ll assign later)
  • Right click on Users and click “Create User…”
  • Enter a username (e.g. “matt”) and a password (twice) and click OK:
    image
  • Advanced Note: If you have a number of users that will all have the same permissions, it may make sense to create a group and add all of those users to that group.  Then when adding permissions to the repositories, you can just add the single group instead of adding each user. (Not shown.)

Create Repository

  • Right click on Repositories and click “Create New Repository…”
  • Enter a (case-sensitive) repository name and click OK:
    image
  • Advanced Note: If you know how to organize and use the typical Subversion directory structure (trunk, branches, tags), then check the box to automatically create those subdirectories in your repository.  If you don’t know why you’d need those, then don’t worry about it :)

Set Repository Permissions

  • Now we need to set the permissions of our newly-created Dissertation repository, so right click on Dissertation and click “Properties…”
    image
  • We probably don’t want to give everyone read/write access to our Dissertation (:P), so the first thing we do is select Everyone and click “No Access”.
  • Now we need to give permission to ourselves, so we click “Add…”, select “matt” and then OK:
    image
  • This leaves us with the following screen, showing that user matt has read/write access to the Dissertation repository:
    image
  • This is exactly what we’re after!  Feel free to tweak to your own needs.  VisualSVN makes things incredibly easy to configure (as opposed to the alternative of hand-editing text files.)

Now we have the Subversion server completely installed, configured, and running.  The next step is to install a Subversion client so we can access our file repository.

Install TortoiseSVN

TortoiseSVN is the most useful Subversion client out there.  It is an “explorer addin” which adds functionality to your Windows Explorer windows.  When you check out a repository (a local copy of the files that you can edit) from the remote Subversion server, it shows the status of each file.  Unedited (current) files show up with green checkmarks beside them, files with changes have red X’s, and files not in the repository have question marks. Here’s an example:

image

You can see that for the most part, no files have been modified.  Only LocalSandbox.cs and some files in the Utilities directory have changed since the last version was checked in. The “bin” and “obj” directories have been intentionally excluded from the repository.

  • Go to the TortoiseSVN download site
  • Download the installer (TortoiseSVN-1.5.5.14361-win32-svn-1.5.4.msi at the time of this writing)
  • Accept the license, keep the default settings, and click Install.
  • After finishing the installation, it may ask you to reboot:
    image
  • Go ahead and click Yes to reboot (since TortoiseSVN gets loaded into Windows Explorer, it actually is crucial to reboot.)

Try Everything Out!

  • Create a directory in C:\ (or wherever) called (for example) “RepositoryCheckout”.
  • It is crucial that you make the distinction between the repository directory (C:\Repositories\* where the Subversion server stores the internal file repository databases) and the repository checkout directory (C:\RepositoryCheckout\*) where we store the local copy of the files as we’re editing them). The repository directory exists only on the server, and the repository checkout directory exists only on the client, but we have them on the same machine now since we have both the server and the client running.
  • Make a subdirectory here called Dissertation:
    image
  • Right click on Dissertation and notice the new TortoiseSVN menu items (SVN Checkout and the TortoiseSVN submenu).
  • Click on “SVN Checkout…”:
    image
  • Now we need to fill in the URL of our repository. To get this, we can back to our VisualSVN Server window.  Since you probably rebooted, it’s in Start > All Programs > VisualSVN > VisualSVN Server Manager. Right-click on the Dissertation repository and then click “Copy URL to Clipboard”. Paste this URL into the “URL of repository” textbox in the TortoiseSVN Checkout window.
  • In my case the URL was “https://ESL0095:8443/svn/Dissertation/”, though https://localhost:8443/svn/Dissertation/ would have worked just as well. Click OK.
  • Because we’re using a secure connection (https instead of plain-old http), TortoiseSVN will ask us if we want to validate an unknown SSL certificate:
    image
  • We trust the certificate (VisualSVN Server just installed a self-signed cert by default), so click “Accept permanently”.
  • Now we’re prompted for our credentials, so enter the username and password that you configured in the VisualSVN Server management utility before:
    image
  • Make sure that the “Save authentication” checkbox is ticked so that you don’t have to enter your username and password for each and every operation in the future.
  • This brings up the “Checkout Finished!” dialog box, showing us that our (empty) repository is a Revision 0:
    image
  • For good measure, let’s add a file to the repository and commit it.
  • Create a file called README.txt in “C:\RepositoryCheckout\Dissertation”:
    image
  • Right-click on README.txt > TortoiseSVN > Add… and click OK, then OK:
    image
  • This will show a blue plus sign on the file, indicating that it was added to the local repository:
    image
  • Now we just need to commit our changes to the local repository back to the Subversion server, so go back up one directory to C:\RepositoryCheckout
  • Right-click on the Dissertation folder and select “SVN Commit…”
  • Enter a log message describing what changed in this commit:
    image
  • After clicking OK, TortoiseSVN will commit our changes to the server and, if successful, indicate that we now have “Revision 1″ of the file repository!
    image

Conclusion

Well, that wraps it up!  Hopefully that is enough information to get started using Subversion to keep track of your files.  There are a lot more advanced topics I haven’t covered here — if you have questions, feel free to leave a comment.

The best way to learn SVN is just to set up a “sandbox” repository and play around :)   Create files, add files, edit files, commit files, delete files, update files — go so far as to create two folders containing checked-out files (simulating two machines) and mess around with things until you are comfortable and confident enough to trust it with all of your files.  It took me a couple hours or so before I felt ready.

If you want to dig deeper, the Subversion web site has a lot of good information. Also, there is a great book called “Version Control with Subversion” available for free online.

Hope that helps! :)

AddThis Social Bookmark Button

Free Software for Students

October 28th, 2008 matt Posted in Programming 2 Comments »

DreamSpark

Microsoft announced awhile back that they were making much of their enterprise-level software available to students FOR FREE.  Yes, you heard that right — it’s a FREE DOWNLOAD. :)

Hop on over to Microsoft DreamSpark and check it out.

I was able to obtain:

  • Visual Studio 2008 Professional (full version, not a trial, and not the Express edition)
  • Visual Studio 2005 Professional (if for some reason you want the old version)
  • Windows Server 2008 Standard
  • SQL Server 2008 Developer Edition
  • Microsoft Expression Studio 2
  • XNA Game Studio
  • Virtual PC 2007

The only catch is that:

In order to get this software from Microsoft at no charge, you will be asked to establish or verify your student status once every 12 months.

As an Ohio State student, the only thing that I had to do was log in with my university-given username/password using the userversity-administers Shibboleth system.  Other universities may operate the authentication process differently.

MSDNAA

While we’re on the theme of free software for college students, you may want to ask your university departmental IT staff if they have a subscription to MSDNAA – Microsoft Developers Network Academic Alliance.  I know that at Ohio State, both the Computer Science department as well as the Electrical Engineering department have subscriptions.  If you are enrolled in a class offered by either department, then you have permission (double-check me on this) to download free software from a much broader list.

I just looked and the software available to departments having MSDNAA subscriptions is pretty hefty:

  • .NET Framework 1.1 SDK
  • .NET Framework SDK 1.1
  • Access 2003
  • Access 2007
  • BizTalk Server 2006 Enterprise Edition
  • BizTalk Server 2006 R2 Developer Edition (x86 and x64)
  • Commerce Server 2007 Developer Edition
  • Compute Cluster Pack
  • Compute Cluster Pack SDK
  • Customer Care Framework 2008 (v3.0)
  • Desktop Optimization Pack 2007
  • Exchange Server 2000 Enterprise Edition
  • Exchange Server 2003 Enterprise Edition
  • Exchange Server 2007 Enterprise Edition
  • Exchange Server 2007 Standard Edition
  • Expression Blend
  • Expression Blend 2
  • Expression Design 2
  • Expression Encoder 2
  • Expression Media 2
  • Expression Studio
  • Expression Studio 2
  • Expression Web
  • Expression Web 2
  • Forefront Client Security (x86 and x64)
  • Forefront Security for Exchange Server with Service Pack 1 (x64)
  • Forefront Security for SharePoint with Service Pack 1 (x64)
  • Forefront Server Security Management Console (x86)
  • Host Integration Server 2006
  • InfoPath 2003
  • InfoPath 2003 Toolkit for Visual Studio Tools for Office 2005
  • InfoPath 2007
  • ISA Server 2006 Enterprise Edition
  • IT Academy Course: Database Developer
  • IT Academy Course: Web Developer
  • IT Academy Course: Windows Client
  • IT Academy Course: Windows Developer
  • IT Academy Course: Windows Server
  • MapPoint 2004 European
  • MapPoint 2004 North America
  • MELL – Developer Edition for MSDNAA
  • MSDN Library – April 2007
  • MSDN Library – December 2006
  • MSDN Library – May 2006
  • MSDN Library (Visual Studio .NET) (Jan 2004)
  • MSDN Library for Visual Studio 2005
  • MSDN Library for Visual Studio 2008
  • MSDN Library for Visual Studio 6.0
  • MS-DOS 6.0
  • Office Accounting Professional 2007
  • Office Accounting Professional 2008
  • Office Business Scorecard Manager 2005 with SP1
  • Office Communications Server 2007 Enterprise Edition
  • Office Groove 2007
  • Office Groove Server 2007
  • Office Project Portfolio Server 2007
  • Office Project Server 2007
  • Office SharePoint Server 2007 Enterprise
  • Office SharePoint Server 2007 Standard
  • OneNote 2003
  • OneNote 2007
  • Project Professional 2002 (Single-User)
  • Project Professional 2003
  • Project Professional 2007
  • Project Server 2003
  • SharePoint Designer 2007
  • SharePoint Portal Server 2003
  • SQL Server 2000 Developer Edition
  • SQL Server 2000 Enterprise Edition
  • SQL Server 2000 SP3a
  • SQL Server 2005 Developer Edition – 32-bit
  • SQL Server 2005 Developer Edition – 64-bit Extended
  • SQL Server 2005 Developer Edition – 64-bit Itanium
  • SQL Server 2005 Developer Edition – DVD
  • SQL Server 2005 Express Edition
  • SQL Server 2005 Standard Edition – 32-bit
  • SQL Server 2005 Standard Edition – 64-bit Extended
  • SQL Server 2005 Standard Edition – 64-bit Itanium
  • SQL Server 2005 Workgroup Edition – 32-bit
  • System Center Capacity Planner 2006 with Service Pack 1
  • System Center Configuration Manager 2007
  • System Center Data Protection Manager 2007
  • System Center Essentials 2007
  • System Center Mobile Device Manager 2008 (x64)
  • System Center Operations Manager 2007
  • System Center Reporting Manager 2006
  • System Center Virtual Machine Manager 2007 (x86/x64)
  • Systems Management Server 2003
  • Virtual PC 2004
  • Virtual PC 2007
  • Virtual PC 2007 64bit
  • Virtual PC for Mac 7.0.2
  • Visio for Enterprise Architects
  • Visio Professional 2002 (Single User)
  • Visio Professional 2003
  • Visio Professional 2007
  • Visual Basic 2005 Express Edition
  • Visual Basic 6.0 Enterprise Edition
  • Visual C# 2005 Express Edition
  • Visual C++ 2005 Express Edition
  • Visual J# .NET
  • Visual J# 2005 Express Edition
  • Visual SourceSafe 6.0d
  • Visual Studio .NET 2003 Professional – Full Install
  • Visual Studio .NET 2005 Professional – Full Install
  • Visual Studio .NET Academic Student Tools 2003
  • Visual Studio .NET Academic Teaching Tools 2003
  • Visual Studio .NET Professional 2002 (Full)
  • Visual Studio .NET Professional 2003
  • Visual Studio .NET Professional 2003 Prerequisites
  • Visual Studio 2005 Professional Edition Beta 2
  • Visual Studio 2005 Professional Edition
  • Visual Studio 2005 Standard Beta 2
  • Visual Studio 2005 Standard Edition
  • Visual Studio 2005 Team Foundation Server Beta 2
  • Visual Studio 2005 Team Foundation Server Trial Edition
  • Visual Studio 2005 Team Suite
  • Visual Studio 2005 Team Test Load Agent Beta 2
  • Visual Studio 2005 Tools for the Microsoft Office System
  • Visual Studio 2008 Professional Edition (x86 and x64 WoW)
  • Visual Studio 2008 Team Foundation Server Workgroup Edition (x86 and x64 WoW)
  • Visual Studio 6 Pro
  • Visual Studio Team System 2008 Team Suite (x86 and x64 WoW)
  • Visual Web Developer 2005 Express Edition
  • Windows 2000 Advanced Server (with SP4)
  • Windows 2000 Professional (with SP4)
  • Windows 2000 Server (with SP4)
  • Windows 2000 SP 4
  • Windows CE .NET 4.2
  • Windows Embedded CE 6.0
  • Windows Server 2003 Enterprise Edition
  • Windows Server 2003 Enterprise Edition – 64 Bit
  • Windows Server 2003 R2 Enterprise Edition with SP2
  • Windows Server 2003 R2 Enterprise x64 Edition with SP2
  • Windows Server 2003 Standard Edition
  • Windows Server 2003 Web Edition
  • Windows Server 2008 Enterprise and Standard
  • Windows Server 2008 Enterprise and Standard 64bit
  • Windows Services for UNIX 3.0
  • Windows SharePoint Services 3.0 with SP1 (x64)
  • Windows Vista Business 64bit
  • Windows Vista Business 64bit with SP1
  • Windows Vista Business
  • Windows Vista Business with SP1
  • Windows Vista Service Pack 1 (32bit, 64bit)
  • Windows Web Server 2008
  • Windows Web Server 2008 64Bit
  • Windows XP Embedded
  • Windows XP Professional (Single User)
  • Windows XP Professional (Single User) 64bit Edition
  • Windows XP Professional with SP1a (Single User)
  • Windows XP Professional with SP2 (Single User)
  • Windows XP Tablet PC Edition 2005
  • XNA Creators Club Online Academic Subscription

When you download a software title, you actually "check out", though the software has a unit price of $0.00.  The system makes sure that you only receive 1 license key (if required).

I feel like a kid in a candy store :)

Keep in mind, though, that these software titles are for educational use only — you can’t give them away and if you’re going to use them to make money you need to buy the full version.

Hope that helps! :)

AddThis Social Bookmark Button

Visual Studio 2010 and .NET Framework 4.0 are out!

October 27th, 2008 matt Posted in Programming No Comments »

It’s official — a community technology preview of Visual Studio 2010 and .NET 4.0 are available for download!

Also, if you haven’t heard, Parallel Extensions have been rolled into .NET 4.0. This is fantastic news.  I guess they’re not Parallel Extensions anymore. :)

How about that fancy new .NET logo? Very slick.

I saw the announcement on Bart’s page pointing to the official announcement by Somasger, but the page is taking forever to load.  I’m sure that blogs.msdn.com is getting positively hammered this week with PDC going on in LA.

Also of note is the announcement of the Windows Azure Service Platform which will allow cloud computing to be hosted in Microsoft datacenters and communicate with RESTful endpoints. Here’s another Channel9 video.

Speaking of REST, Steve Maine has announced the availability of the WCF REST starter kit. I just added it to my long list of cool stuff coming out of PDC that I’ll be downloading and trying out here soon.

AddThis Social Bookmark Button

NSandbox: An Introduction

October 13th, 2008 matt Posted in Programming No Comments »

In my last post I introduced a new utility library called NSandbox that makes interacting with AppDomains, or sandboxes, incredibly easy.  I didn’t go into specifics about how to use it, so let’s dig into some code.

Overview

First off, what is an AppDomain and why do we need to create more? From the MSDN page,

Application domains, which are represented by AppDomain objects, help provide isolation, unloading, and security boundaries for executing managed code.

So, we want to execute code in its own AppDomain when:

  • It might bring down our process and we want to isolate its failures.
  • We need to be able to unload the assemblies that it is using.  By design, the .NET framework automatically loads assemblies containing referenced types into the AppDomain requiring those types.  However, it does not provide a means to unload that assembly while the process is running without unloading the entire AppDomain.
  • The code we are executing has different security requirements than our application. We might be executing partially untrusted code and need to lock down what permissions it has (e.g. no file access, etc).
  • We need to specify a new application configuration file (e.g. App.config) for a particular piece of code.  The .NET framework lets you specify a configuration file to use when creating a new AppDomain. This can be quite useful, for example, when testing WCF services which are usually configured via the application configuration file.

For more background information about AppDomains, I’d highly recommend Juval Lowy’s book "Programming .NET Components". I can’t tell you how useful this book has been, and how many times I’ve referred back to it.

Architecture

It helps to have a visual representation of the way NSandbox abstracts away the AppDomain management, so here’s a nice diagram. When every .NET application starts (the orange process box), a default AppDomain is created in which everything runs (the top blue box). It loads its configuration information from the App.config file (renamed to the executing assembly’s name + .config), if one is available.

image

NSandbox then provides two abstractions — a "local sandbox" and a "remote sandbox".  A local sandbox is an object that resides in the current AppDomain that knows how to create and initialize a remote sandbox object in another new AppDomain. In the above picture, a local sandbox is created that:

  • Makes a new directory to serve as the base directory for the new AppDomain
  • Copies all required files to the new directory (e.g. all required DLLs, data files, any files that the sandboxed code needs, etc)
  • Writes a new Sandbox.config file (if necessary)
  • Creates a new AppDomain (using this Sandbox.config file if necessary)
  • Initializes a new instance of the remote sandbox object in the new AppDomain

For the sake of usability, NSandbox provides a SandboxManager as a collection of local sandboxes, allowing all sandboxes to be set up or torn down at the same time.

Communication between local and remote sandboxes can go both ways. The local sandbox can invoke methods on the object in the remote sandbox.  Also, the local sandbox can subscribe to events fired by the remote sandbox (if it’s careful, more on this later).

Under the hood everything is using .NET Remoting, but I’ve tried to hide all of the details involving MarshalByRefObject and serialization.

Now that we’ve covered the basics of NSandbox, let’s dive into an example.

Remote Sandbox

In this example, we’ll set up a single remote sandbox (with a custom config file), invoke methods, and subscribe to an event.

The first thing we need to do is define the object that will live in the remote sandbox.  It must inherit from RemoteSandboxBase which is part of NSandbox.  Here’s our simple version of RemoteSandbox:

public class RemoteSandbox : RemoteSandboxBase

{

    public int GetAppDomainId()

    {

        return AppDomain.CurrentDomain.Id;

    }

 

    public string GetConfigValue(string key)

    {

        return ConfigurationSettings.AppSettings[key];

    }

 

    public SomethingUsefulResponse DoSomethingUseful(SomethingUsefulRequest input)

    {

        return new SomethingUsefulResponse(input.Message.Length);

    }

 

    public void FireEvent()

    {

        SomethingHappenedEvent.Fire(this, new SomethingHappenedEventArgs("FireEvent called."));

    }

 

    public event EventHandler<SomethingHappenedEventArgs> SomethingHappenedEvent;

}

Cross-AppDomain Objects

Pretty self-explanatory, and nothing too complicated going on here.  One thing we need to pay careful attention to — any type which will be making the journey between AppDomains MUST be marked as Serializable.  So, in this example, we see that DoSomethingUseful takes a SomethingUsefulRequest and returns a SomethingUsefulResponse, so both of these must be marked as Serializable.  In addition, the SomethingHappenedEventArgs will be traveling as well, so the rule applies here, too.  If any class going across the boundary isn’t marked as Serializable, an exception will be thrown at runtime.

So, here are the implementations of those 3 classes:

[Serializable] // Important!

public class SomethingUsefulRequest

{

    public SomethingUsefulRequest(string message)

    {

        this.Message = message;

    }

    public string Message { get; private set; }

}

 

[Serializable] // Important!

public class SomethingUsefulResponse

{

    public SomethingUsefulResponse(int length)

    {

        this.Length = length;

    }

    public int Length { get; private set; }

}

 

[Serializable] // Important!

public class SomethingHappenedEventArgs : EventArgs

{

    public SomethingHappenedEventArgs(string whatHappened)

        : base()

    {

        this.WhatHappened = whatHappened;

    }

    public string WhatHappened { get; private set; }

}

Configuration Files

Now we need to talk about is the creation of the configuration file for the remote sandbox.  Each local sandbox has an associated IConfigurationWriter. This implementation simply writes the Sandbox.config file for the new AppDomain.  Of course, if no configuration file is needed, then a value of null for the IConfigurationWriter can be used.

At the current time, only one implementation of IConfigurationWriter is provided, though you are more than welcome to create (and contribute!) your own.  The ParameterizedConfigurationWriter is constructed to point to a template configuration file but then performs a search/replace throughout the file looking for variable names in the format $variableName$.  For example, if we have a file named SandboxTest1.config:

<configuration>

  <appSettings>

    <add key="thing1" value="$var1$"/>

    <add key="thing2" value="$var2$"/>

  </appSettings>

</configuration>

we can specify the values to replace $var1$ and $var2$ with using:

ParameterizedConfigurationWriter sandbox1Config = new 

    ParameterizedConfigurationWriter("SandboxTest1.config");

sandbox1Config.Variables.Add("var1", "Variable 1");

sandbox1Config.Variables.Add("var2", "Variable 2");

Of course, if no variables need to be replaced in the file, then a ParameterizedConfigurationWriter can still be used without any variable/value pairs added to the Variables collection.  The ParameterizedConfigurationWriter will then just copy the template file to the remote sandbox directory.

Local Sandbox

Now let’s put all of these pieces together and set up the local sandbox:

LocalSandbox<RemoteSandbox> sandbox1 = new LocalSandbox<RemoteSandbox>("sandbox1", sandbox1Config);

sandbox1.DependentFiles.Add("NSandbox.Tests.dll");

sandbox1.DependentFiles.Add("NSandbox.dll");

The local sandbox is a generic class which accepts one type argument — the type of object to create in the remote AppDomain. In the constructor, we also specify a "friendly name" (sandbox1 in this case) and the IConfigurationWriter to use. The friendly name is used as the directory name for the sandbox and must be unique across all local sandbox instances.

Then we add the names of all required files that must be present in the AppDomain’s ApplicationBase directory.  The local sandbox takes care of copying these files for us.

SandboxManager

Next we create a new SandboxManager and add this local sandbox to its list of sandboxes.

SandboxManager manager = new SandboxManager();

manager.Sandboxes.Add(sandbox1);

manager.SetupAllSandboxes();

// Use the sandboxes here

manager.TeardownAllSandboxes();

We can then use the sandboxes between calls to SetupAllSandboxes and TeardownAllSandboxes.

The default constructor here uses the currently-executing assembly’s path as the root directory for all operations.  The friendly name subdirectories for each sandbox are relative to the SandboxManager’s root directory. You can also specify your own fully-qualified root directory, but then all of the filenames specified in the local sandbox should be fully-qualified.

Using the remote sandbox

Ok, now we have our sandboxes created and we can actually do something useful with them :)

First, we need to get a reference to the remote sandbox from the local sandbox.  Because we’re using .NET Remoting, we’re actually getting a reference to a proxy to the remote sandbox, but we don’t really need to worry about that.

RemoteSandbox remoteSandbox1 = sandbox1.RemoteSandbox.As<RemoteSandbox>();

Now we can call the GetAppDomainId method on the RemoteSandbox object, and make sure that their Ids aren’t the same (on my computer the Ids were 3 and 4, respectively):

int localId = AppDomain.CurrentDomain.Id;

int remoteId = remoteSandbox1.GetAppDomainId();

Assert.AreNotEqual(localId, remoteId);

Now we can grab some configuration values in the remote AppDomain to make sure that the ParameterizedConfigurationWriter worked correctly:

string thing1Value = remoteSandbox1.GetConfigValue("thing1");

Assert.AreEqual("Variable 1", thing1Value);

string thing2Value = remoteSandbox1.GetConfigValue("thing2");

Assert.AreEqual("Variable 2", thing2Value);

Next, we can subscribe to an event that is fired from the remote sandbox, and then fire it.

bool eventFired = false;

remoteSandbox1.SomethingHappenedEvent += (new RemoteEventWrapper<SomethingHappenedEventArgs>(

    (sender, args) =>

    {

        eventFired = true;

    })).LocalCallback;

remoteSandbox1.FireEvent();

Assert.IsTrue(eventFired);

The RemoteEventWrapper class is the secret to subscribe to remote sandbox events.  I explained why events can’t be subscribed to in the normal way back in this post (in the section "Firing Events Across AppDomain Boundaries") which references this bugfix from Microsoft. I think the RemoteEventWrapper around an anonymous method is an elegant solution to the problem.

As the final test, we can create a (serializable) object in the local sandbox, serialize it across the boundary, and invoke a method with it in the remote sandbox. The return value is also a serializable type.

string message = "This is a test.";

int length = remoteSandbox1.DoSomethingUseful(new SomethingUsefulRequest(message)).Length;

Assert.AreEqual(message.Length, length);

Conclusion

And….that’s a wrap! All of the code in this post is available in the NSandbox SVN in the NSandbox.Tests project.

If this sounds useful, head on over to Sourceforge and download the installer.  I wanted to license NSandbox with the BSD license (closer to public domain than LGPL or GPL) so that both open-source and commercial projects can use the code.

In my next post I’ll talk about using NSandbox to do full-blown integration testing with WCF services.

Hope that helps! :)

AddThis Social Bookmark Button

Announcing: NSandbox on Sourceforge

October 9th, 2008 matt Posted in Programming 5 Comments »

Have you ever needed to:

  • Use a "plugin" architecture?
  • Unload an assembly after using it?
  • Execute arbitrary code with different security requirements in its own "sandbox"?
  • Wanted to test multiple WCF services from the same process, but with different configuration files?

…then NSandbox is the utility library that you’ve always needed :)

NSandbox is a small library that I’ve thrown together that lets you create, manage, and unload any number of "sandboxes", or AppDomains. It abstracts away the standard .NET remoting infrastructure (MarshalByRefObject and friends), letting you easily invoke methods and subscribe to events on objects in other AppDomains.

Lately I’ve been using NSandbox to do quite a bit of WCF integration testing.  Typically this would involve building, deploying, starting, debugging, and stopping a number of services, possibly on different machines.  In a tight development loop this can be very cumbersome — sometimes I would spend more time deploying and starting/stopping the services than I would on development. In addition, I usually also had 4-5 instances of Visual Studio open at the same time in an attempt to set breakpoints in both client and server code.

I came up with a way that I could host all of my WCF services within the same process (only 1 Visual Studio debugger!) by separating each service into its own AppDomain. This is a natural match since each WCF service is (typically) configured by an App.config file, and each AppDomain can have its own configuration file specified. Granted, since everything is running in a single process a little more care must be given to the multithreading aspects, but in my experience using NSandbox has been an incredible productivity booster.

So, if you haven’t already, hop over to Sourceforge, download the MSI installer, and try out NSandbox. I’d love to hear any feedback that you have.

Included in NSandbox 0.1:

  • bin\NSandbox.dll (reference this from your project)
  • doc\NSandbox.chm (compiled documentation)

There are a few good example projects in the SVN code. In particular check out the NSandbox.Tests project. I’m working on incorporating the example code into the installer for the next version (hopefully soon). The examples are built into NUnit tests, though they are actually full-blown integration tests, not just unit tests of the service implementations.

I’ll be posting more about the integration testing soon :)

Enjoy!

AddThis Social Bookmark Button

CCR 101 Download Available

October 6th, 2008 matt Posted in Programming 1 Comment »

In my last post about the CCR, I made heavy reference to the excellent "CCR 101" blog post series by Nick Gunn.

I’m pleased to announce the availability of a complete download of all of his posts in one easy-to-print Word document, as well as a Visual Studio solution containing all ready-to-run examples.

I found these posts quite helpful when learning CCR basics and wanted to make it more accessible so others wouldn’t need to spend time copy/pasting code in order to try the examples.

You can snag the zip file containing everything over at the Code Samples page.

Thanks Nick!

Hope that helps someone :)

AddThis Social Bookmark Button

Generating GUIDs for WiX with a Visual Studio Macro

September 24th, 2008 matt Posted in Programming 1 Comment »

Lately I’ve been doing some work with WiX (Windows Installer XML) and have needed to generate fresh GUIDs frequently.

For those infrequent uses, the online UUID Generator worked great, but WiX needs a lot of GUIDs and I got tired of copy/pasting them.

Unfortunately there’s no built-in support for this, but it’s fairly straightforward to set up a VB.NET macro for this purpose. I ran across the macro code over here which shows how to bind to a keystroke, but I’ll illustrate how to bind the macro to a toolbar button instead.

  • Bring up the Macro IDE (Tools > Macros… > Macros IDE…)
  • Add a new module called "GuidModule"
  • Copy/paste the following code into the GuidModule:

    REM Insert a new GUID at the insertion point

    Sub InsertGUID()

        Dim ts As TextSelection = ActiveDocument().Selection

        Dim guid As System.Guid = System.Guid.NewGuid()

        ts.Insert(guid.ToString().ToUpper())

    End Sub

Your screen should look like this:

image

  • Hit the close button in the corner to go back to the main Visual Studio window
  • Right click on the toolbar window to bring up the list of toolbars, and click Customize… at the bottom

image

  • Click New…
  • Give the toolbar a name (e.g. "Guid") and click OK
  • The new toolbar will appear directly to the right of the Customize window — now drag it up to the top toolbar

image

  • Now click on the Commands tab of the Customize window and select the Macros category:

image

  • Select the MyMacros.GuidModule.InsertGUID command and drag it up to the Guid toolbar
  • Right-click on the button and change the name to "Guid"

image

  • Click Close on the Customize window and you’re done

Now, try it out by positioning the cursor somewhere in a text file that you need a new GUID to be inserted and press the Guid button.  The first click takes a second or so to load the macro engine.

image

Bam! I love the smell of freshly-picked GUIDs.  They’re so……unique. (Sorry, that was really bad.)

Hope that helps!

AddThis Social Bookmark Button