Implementing the RowViewModel – Part 2

Part 2 – Getting Data into the Grid

In Part 1, we setup the projects necessary for a standard business application using IdeaBlade DevForce for the Model, MVVM Light for the ModelView and a Telerik RadGridView in the View.

In Part 3, we will follow through the binding process to see some of the challenges posed when making the grid editable.

In Part 2, we will make the changes necessary to make the grid editable.

Requirements

For this part of the sample, the requirements are as follows:

  1. Show Orders in the Rows of the Grid.
  2. Make the Grid Editable.
  3. Save changes to the Orders with a Save Changes button.

Showing the Orders in the Grid

This will require adding an Orders property to the MainViewModel; populating that property and then binding the Orders property to the grid.

  1. Make sure there is a reference in the Web project to the server-side Model project.
  2. Open the MainViewModel.cs file.
  3. Remove the Welcome property.
  4. Open the ViewModel\MainViewModel.cs file.
  5. Use the mvvminpc Snippet to add an Orders property.
    /// <summary>
    /// The <see cref="Orders" /> property's name.
    /// </summary>
    public const string OrdersPropertyName = "Orders";
    
    private ObservableCollection<order> _orders;
    
    /// <summary>
    /// Gets the Orders property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public ObservableCollection<order> Orders
    {
        get
        {
            return _orders;
        }
    
        set
        {
            if (_orders == value)
            {
                return;
            }
    
            //var oldValue = _orders;
            _orders = value;
    
            // Remove one of the two calls below
            //throw new NotImplementedException();
    
            // Update bindings, no broadcast
            RaisePropertyChanged(OrdersPropertyName);
    
            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            //RaisePropertyChanged(OrdersPropertyName, oldValue, value, true);
        }
    }
  6. Next, add a method to fill the collection.
    private void GetOrdersAsync()
    {
        var em = new NorthwindIBEntities();
        var qry = em.Orders;
        em.ExecuteQueryAsync(qry, args =>
             this.Orders = new ObservableCollection<order>(args.Results));
    }
  7. Next, add a call to the new method in MainViewModel constructor:
    public MainViewModel() 
    { 
        GetOrdersAsync();
  8. Finally, add a binding to the XAML to show the Orders in the Grid.  (Set the ItemsSource of the RadGridView to Orders.)
    <telerik:RadGridView Name="radGridView1" ItemsSource="{Binding Path=Orders}" Height="775" Width="1000" />
  9. Build and Run.  After a moment or two, you should see the grid, fully populated with Orders.
    image

Making the Grid Editable

For once, the default behavior is desirable.  We get this for free because the RadGridView is editable by default.  Due to the magic of Binding, the Order objects are getting updated whenever a cell in the grid is edited.

Saving the Changes

Saving those changes will require us to have a button bound to an ICommand that will tell the EntityManager to save all the changes.

  1. In MainPage.xaml, add a button to the StackPanel above (or below) the RadGridView.
    <Button Content="Save" Height="23" Name="SaveAllButton" Width="75" HorizontalAlignment="Left" />
  2. In MainViewModel.cs, add a new RelayCommand named SaveAllCommand.
    public RelayCommand SaveAllCommand
    {
        get;
    	private set;
    }
  3. In the MainViewModel constructor, add a line to instantiate the command:
    SaveAllCommand = new RelayCommand(this.SaveAllOrders);
  4. Now add the SaveAllOrders method and the SaveAllButtonEnabled property:
    private void SaveAllOrders()
    {
        this.SaveAllButtonEnabled = false;
        _entityManager.SaveChangesAsync(args => 
            this.SaveAllButtonEnabled = true);
    }
    
    public bool SaveAllButtonEnabled
    {
        get
        {
            return _saveAllButtonEnabled;
        }
        set
        {
            _saveAllButtonEnabled = value;
            RaisePropertyChanged("SaveAllButtonEnabled");
        }
    }
  5. Now you can go back to the button to set the bindings:
    <Button Content="Save" Height="23" Name="SaveAllButton" Width="75" HorizontalAlignment="Left" IsEnabled="{Binding Path=SaveAllButtonEnabled}" Command="{Binding Path=SaveAllCommand}" />
  6. Build and Run. After a moment or two, you should see the grid, fully populated with Orders. Try editing some of the orders and hit Save All. Refresh the page to see that the changes were saved.

What’s next?

So now you have an editable grid. So far, we have not needed the RowViewModel. If you only want SaveAll functionality, the default behavior of the grid will suffice. The grid lets you edit any cell all the time and the bindings keep the model up to date. A simple call to entity manager to save the changes and all is well.
However, if you want some entity specific functionality, you will find it quite cumbersome to try to deal with this within the context of the grid’s ViewModel as it is really only concerned with the grid and entire grid related actions (such as Save All).

In Part 3, we will add some entity specific requirements so we can see how to use the RowViewModel to make working with the entities in the grid much simpler.

Implementing the RowViewModel – Part 1

 

Part 1 – Setting up the Projects

In my earlier post here, I introduced the concept of a RowViewModel to make editable grids using the MVVM pattern.  In this post, I will demonstrate how to implement the RowViewModel using a combination of IdeaBlade DevForce for the Model, MVVMLite for ViewModel support and Telerik’s Silverlight RadGridView for the View.

Prerequisites:

  1. IdeaBlade DevForce 6.0.7 or later.
  2. Telerik Silverlight Controls 2010.3 or later.
  3. MVVM Light Toolkit
  4. VisualStudio 2010 and Silverlight 4
  5. Silverlight 4 Toolkit

Assumptions:

  1. We’ll use IdeaBlade’s sample database:  NorthwindIB.  This can be found in the \Program Files\DevForce 2010\ folder.
  2. I have way too many VS add-ins installed so my screen shots may not appear as your screen does.
  3. I do use JetBrains Resharper and Telerik’s JustCode, so some of the refactorings and shortcuts may not be available if you do not have these tools.

Creating the Beginning State

  1. Per the article and sample shown at MVVM Light with DevForce, we will create a sample app using the MVVM Light SL4 template.  (I.e. Set up their MvvmLite1 example.)
    image
  2. Then add the DevForce Silverlight Application project.
    image
  3. Delete the README_FIRST files.
  4. In the Model project:
    1. Delete App.xaml and MainPage.xaml.
    2. Rename the project with SL suffix.  Do not rename the Assembly with the SL suffix and do not change the namespace.
  5. In the Application project:
    1. Add a reference to the Model project.
    2. Add references to the DevForce assemblies referenced in the Model project.
      image
    3. In the properties for the DevForce assemblies, change the Copy Local to True and the Specific Version to False.
      image
    4. Add a reference to System.Runtime.Serialization.
  6. In the Web project:
    1. Rename the web project to remove the word Model.
    2. In the project properties:
      1. Rename the Assembly and the namespace.
      2. On the Silverlight Applications tab, remove the dead DevForce Silverlight app project (if present).
        Add the Silverlight Application (e.g. RVMSample). 
    3. Delete the test HTML page and the Default.aspx page.
    4. Set the Web project as the Startup Project. 
    5. Set the new test ASPX page as the Start Page.
    6. Delete the XAP file from the ClientBin folder.
  7. Save and Close the solution.
  8. Rename the project folders to match the project names.
  9. Edit the .SLN file in a text editor to correct the folder names there too. 
    image
  10. Open the solution in VS.
  11. Build and Run.  Nothing so far has changed the functionality so it should work fine:   
    image    

Creating the Server-Side Model Project

So far so good.  We have setup the three-project solution.  Unfortunately, this means we’re going to load the EDMX into the Web project, which hardly seems fitting.  Let’s create a server-side project to house the server side Model.

  1. Add a regular Class Library project as the server side Model.  This should be named application.Model.
  2. Delete Class1.
  3. In the Web project, add a reference to the application.Model project.
  4. Add an ADO.Net Entity Data Model name it NorthwindIBModel.
  5. Select to Generate from database.
  6. Connect to the NorthwindIB database.
  7. Select the following tables:
    Customer
    Employee
    Order
    OrderDetail
    Product
  8. Change the namespace to application.Model.
  9. Wait while the Entity Manager and IdeaBlade do their code generation.  IdeaBlade will also make a link from the Model.SL project to the Model project so they share code.
  10. Copy the new connectionString settings from app.config in this project to web.config in the web project.
  11. Build the solution to make sure all the references are configured properly.  Run the app.  See nothing has changed yet. 🙂

Adding the Grid to the View

Great, now we have client-side (Model.SL) and server-side (Model) model projects, a Silverlight application project and a Web project to host it all in.  Let’s go ahead and add the Telerik Grid to the project, then we can finally start looking at the Row-View-Model pattern.

  1. In the application project, open the MainPage.xaml.
  2. Change the Width and Height of the page to 1000 x 800.
  3. Remove the TextBlock that is there.
  4. Change the <Grid> to a <StackPanel>.
  5. In the <StackPanel>, drag and drop a Telerik RadGridView from the Toolbox.
  6. Change the Width and Height of the RadGridView to 1000 x 800.
  7. Build the solution to make sure all the references are configured properly.
  8. Run the application.  You should see the empty Telerik grid in your browser:
    image

Ta da!  All that work to set up the beginning state for exploring RVM.  In my next posting, you will get the requirements for the grid and see how we can use the RowViewModel to make in-line grid editing much simpler.

MVVM and the Editable Grid

There is a dirty little secret in the Grid market:  making a Grid Editable, on a row-by-row basis (not in its entirety), is a nightmare.

So, as we all know, MVVM is the cure-all for everything UI, so apply MVVM to the Grid form and away we go.  Right? 

Doh!  Wrong.

You see, hosting the Grid in the View of a form actually ends up making the hassle even worse.  But do not despair, there is a simple-enough solution to this otherwise complex dilemmas.   I call this solution:  the RowViewModel.

The what you say?  Heretical mishmash you say?  Read on fearless coder, read on.

Terminology

First, let’s at least agree to some nomenclature.  Failing that, here is MY understanding of MY use of these terms.

View – An unintelligent skin hosting UI controls and bindings and minimal code to call Commands and raise Events.  Can be injected into the View Model at run time.

View Model – All the intelligence behind the View is stored here.  This client side class defines and executes Commands and knows how to respond to events and manipulate UI controls and fields.  This class will pass on all persistence methods to the repository class.  The ViewModel holds a reference to an instance of the client side business object and wraps its properties in ViewModel properties for binding to the UI.  The UI does not bind directly to the business object, but to the ViewModel property instead.  For example, suppose you can’t save a customer until the Name, Phone and City are populated.  The ViewModel owns the state of the Save button (enabled/disabled) and the validation flags for required fields.  It makes sense to put a function in each property setter in the ViewModel for Name, Phone and City that will check whether to enable/disable save.

Repository – A class that knows how to interact with your Data Layer and is responsible for dealing with the persistence methods provided in your ORM framework.  (For example, DevForce has an EntityManager that has a Save method.  The Repository is the only class that should ever call that Save method.)

Business Object – In DevForce 3.5, there’s a client side Silverlight business class that is the synonym of the server-side data class.

Data Object – In DevForce 3.5, the server-side C# version of the business object.  These classes are generated by DevForce from the EntityFramework model.

RowViewModel Conceptual Overview

So here’s the application model for a UI Module with an editable grid.  As an example, let’s imagine we want to provide an editable heirarchical grid with a list of customers in it and a list of their addresses nested underneath each customer row.

First, we need the View and ViewModel for the grid form.

  1.  One View class for the page/tab/control that hosts the grid (e.g. CustomerGridView).

  2.  One ViewModel class backing the page/tab/control that hosts the grid (e.g. CustomerGridViewModel).

The gridView and gridViewModel are responsible for managing interactions around the grid and for actions that affect multiple rows.  For example, "Select All", "Print All", "Expand All", "Print Selected Customers", Filters of all sorts, column sorting, etc.

Second, we need: 

  3.  A RowViewModel class for each row type (e.g. CustomerRowViewModel, AddressRowViewModel).

The gridViewModel holds a collection of the top level <parent>RowViewModels (e.g. CustomerRowViewModels).  Each top level RowViewModel holds a collection of <child>RowViewModels (e.g. AddressRowViewModels).

Lastly, there should be:

  4.  One Repository class to support the functionality represented by the entire page.  This repository is likely inherited from a utility class that provides all the standard repository behavior (persistence, querying, etc.) using generics.

Now that you have been introduced to these classes, here’s how they come together:

Say we have Customers and Addresses.
The Grid itself will be configured as a hierarchical grid with one parent band and one child band.  Where the parent shows each Customer as a row and each Address as a row underneath the Customer row.  Traditionally, you would bind the parent row source to the Customers collection property of the gridViewModel, and the child row source to the Addresses property of the Customer object.

Now, imagine the user starts to edit a cell.  Which cell?  Well, the grid will tell you which cell.  It’s the Customer Rep column for Row 17.  Which customer is bound to Row 17?  Some grids won’t tell you, so you have to jump through hoops to figure it out.  And heaven forbid the grid is sortable because with one click, all your mappings are out of date.  Meanwhile, back to the Customer Rep column.  It’s bound to a combo box.  You have three types of customers:  Volume, Retail, and Educator.  There are different Reps for each type.  Uh-oh.  Now you need, not just any combo box, but a filtered combo that is dependent on the Customer Type (which we’ll assume was selected earlier in the row). 

If you use the Grid’s built-in combo box column type, it is bound to a collection of Customer Reps in the gridViewModel and you can watch as you filter that list and the grid blanks all the rows that have a value that is not in the filtered list.  Yeuch. 

Or you can try a hovering combo that comes to the exact co-ordinates of the cell and hovers above it providing the illusion that it is part of the grid, then you can populate it however you want.  But wait, that means you now have to write all the code to get that combo to work, manage the binding to the instance you need, and get the whole thing to sync properly when you’re done editing it.  Ack!  Oh, and you can’t use the grid’s built-in undo feature any more.

What to do?  Enter the RowViewModel.

Here’s how we bring the RowViewModel into this.

In the parent band, each grid row is a single View for a single RowViewmodel in the gridViewModel.CustomerRowViewModels collection.
Each CustomerRowViewModel holds a collection of its own AddressRowViewModels. 
The child bands (there is one child band for each parent band that has children), have rows, each row in a child band is a View for an AddressRowViewModel.

In this structure, the rows can be bound appropriately and each RowViewModel is responsible for the interactions with 1 and only 1 row in the grid.

Back to our Customer Rep combo box problem.  Now, the CustomerReps collection is a property of the CustomerRowViewModel and the grid’s built-in combobox can be happily bound to the CustomerRowViewModel.CustomerReps collection without complaint.  When the Customer Type changes, the CustomerReps collection is repopulated and the binding will update the combo box automagically.  Yay. No code to translate from Cell to Customer and the tie-in from the CustomerGrid Column binding to the CustomerRowViewModel property is a very standard binding.

So how does this look in code?  I’m going to have to get back to you on that as I put together the code example for this simple scenario.

IdeaBlade DevForce – Model Setup Walk-through – Step 2: The DevForce Projects

Our Problem:


We need to create an Enterprise application that is web-based, has an Excel-ish interface and pulls data from an Oracle database.

Technologies Chosen*:

  • Silverlight for the UI
  • Prism 2 for the modular framework
  • Unity for DI
  • IdeaBlade DevForce for the Business Object Layer and Async functionality
  • MS Entity Framework for the ORM
  • DevArt dotConnect for Oracle (EF Drivers)
  • Oracle 11 Database

* See here for our reasoning.

Prerequisites:

  1. Complete the procedures documented in Step 1
  2. Install IdeaBlade’s DevForce for Silverlight tool.
  3. Install the Silverlight development environment. This comprises:
    1. The Silverlight 3 Developer Runtime
    2. The Silverlight 3 Tools for VS 2008
    3. The Silverlight 3 SDK

Creating the DevForce model projects:


There will be two DevForce model projects, one will be a C# library project that runs on the server, the other will be a Silverlight library that runs in the Silverlight client. The DevForce framework takes care of wiring these two together with a couple of WCF services that are hosted in the Web application that hosts the DevForce components and the Silverlight app.

To create the projects:

  1. Open the Entity Framework model solution created in Step 1 of this walkthrough.
  2. Select Tools | DevForce Object Mapper
  3. DevForce naturally works with EDMX files (Model | Add Entity Model), but we have an EDML file from the devArt Entity Developer, so we have to use File | Open to get to it.

    Select File | Open, change the Files of type to All Files. Select the Model_Widget.edml file and click Open.
    At this point, DevForce has opened the EF model. Now, we have to tell it how we want the projects to be configured.

  4. First, click the New Project button for the Domain Model project.
    The Project Name needs to follow our assembly naming convention, so for this walkthrough, I am using Acme.BirdTrap.Model.Widget (with no suffix).
    I will leave the Project Type and Location at their defaults.
  5. Second, click the New Project button for the Silverlight project.
    The Project Name needs to follow our assembly naming convention, so for this walkthrough, I am using Acme.BirdTrap.Model.WidgetSL (with the SL = Silverlight suffix).
    I will leave the Project Type and Location at their defaults.
  6. Back on the new model tab:
    1. Set the Namespace to: Acme.BirdTrap.Model.Widget
    2. Set the EntityManager name to something more model specific, we use a standard of ModuleEntityManager as the application may need to work with multiple modules’ EntityManagers at the same time.
      I have selected to name the Entity Manager: WidgetEntityManager.

    New Devforce Project Settings

    [Note: See Ward Bell’s essay on the topic of Large Models for more about splitting your model and using multiple Entity Managers.]

  7. Select the Model_WidgetEF.edml branch of the Model tree on the left. You will see the settings available for this EF Model.
    1. Change the DataSourceKeyName to something more model specific, we use a standard of ModuleDataSource as each module/model needs a different DataSource definition.
      I have selected to name the Data Source Key: WidgetDataSource
    2. This is also the place where you inject your own base Entity class implementations into the DevForce model. At the very least, you should create a BaseEntity class where you can put common Entity functionality. Click the Injected Base Types button and add Acme.BirdTrap.Utility.Persistence.BaseEntity to the list, setting it as the default. (In a future posting, I will be examining the Injected Base Types in greater depth.)
    3. The name pluralizer is a great feature of DevForce but it is completely irrelevant to us as devArt’s Entity Developer tool has taken care of pluralization for us.

  8. Click the Save button on the toolbar. DevForce will now create and initialize the two projects we have defined. When it has finished, close the DevForce Object Mapper.
  9. Next, we need to create the BaseEntity class we added to the Injected Base Types earlier.
    1. In the new C# project, Acme.birdTrap.Model.Widget, add a new class named Acme.BirdTrap.Utility.Persistence.BaseEntity that inherits from IdeaBlade.EntityModel.Entity
      using IdeaBlade.EntityModel;
      
      namespace Acme.BirdTrap.Utility.Persistence
      {
          public class BaseEntity : Entity
          {   
          }
      }
    2. In the new Silverlight project, Acme.birdTrap.Model.WidgetSL, add an Existing Item, then navigate to the BaseEntity class you just created in the C# project, drop down the Add button and choose Add as Link.
  10. I bet you wish we were done at this point. We are not. DevForce made some assumptions in generating the projects that we need to fix.

    First, and really only a cosmetic issue, DevForce created a Solution Folder for the DomainModel. You can choose to keep this or not. This whole solution is for my DomainModel, so I do not need this new folder. If I incorporate the Model projects into a larger Module level Solution, then I will use a Solution Folder for the Model projects in that solution, but I do not need one here. To remove the folder, I drag the two new projects up out of the folder into the Solution level and then Remove the folder.

  11. Second, and by far more serious, DevForce pulled in a bunch of referenced components, some of theirs, some of the .Net Framework’s and some from the Silverlight SDK.
    There are three places where referenced assemblies can safely live:

    1. \WINDOWS\Microsoft.NET\Framework\**.*
    2. \Program Files\Reference Assemblies\**.*
    3. Your solution’s dependencies\**.*

    1. Examining the C# project (Acme.BirdTrap.Model.Widget), we find the IdeaBlade assemblies are referenced from Program Files. We can change that by: first, removing the Ideablade.Core, Ideablade.EntityModel, Ideablade.Validation,assemblies; then adding them back from the dependencies\IdeaBlade DevForce\ folder.
    2. Examining the Silverlight project (Acme.BirdTrap.Model.WidgetSL), we find the IdeaBlade Silverlight assemblies are referenced wrong, which can be corrected as above, only adding back from the dependencies\IdeaBlade DevForce\SilverlightAssemblies folder this time.
      However, we also find that the System.ComponentModel.DataAnnotations assembly is being pulled from \Program Files\Microsoft SDKs\ folder. Remove it and add it back from dependencies\Silverlight\Libraries\Client\.
  12. That’s it, right? We’ve created the files and all is well. If you try to Build your solution right now, you will get errors originating from the EF project. But it was fine before we started, and we didn’t change it — or did we?
    In fact, we did. When you point the DevForce Object Mapper at the EF project’s EDML file, DevForce adds a bunch of attributes to some of the elements in that file. In doing so, the DevArt Entity Developer notices the EDML has changed and wipes the generated *.designer.cs file. To restore this, you need to re-open the EDML file and regenerate the generated code. But here’s the rub, if you open the EDML file from within Visual Studio, the devArt Entity Developer will only regenerate the code if you make changes to the model. But we don’t want to make changes to the model.
    Instead, open the EDML file from Windows Explorer. This will open the Entity Developer and reveal a Generate Code button on the toolbar:
    Generate Code button
    Clicking this button, will regenerate the missing generated code without requiring a model change. You can then exit the Entity Developer.
  13. DONE.

Conclusion


In this part of the walk through, we have created the pair of DevForce C# and Silverlight projects that contain our Domain Model.
The solution successfully Builds and the EF unit test we created in Step 1 still passes. Now we need to create a pair of Unit Test projects to ensure that the DevForce framework is configured properly and can successfully CRUD the database through the EF layer. But that will have to wait until the next part of the walk through.

Until then: I’m off to take the dog for a walk! Woof!

IdeaBlade DevForce – Model Setup Walk-through – Background

I know the world is about to change in April when VS2010 goes live, however, we are still using VS2008 and will be for at least a few more weeks.  In the hopes that this walk-through provides some insight to someone, even if it is just me, here goes.

Background

We are  creating a Silverlight application for several reasons:

  1. Web development is not nearly complex enough, so we sought out a unique challenge involving the newest, least documented, voted most-likely-to-be-completely-re-done-in-the-next-version technology (excepting WWF, I mean, WF, which will probably hold that distinction for years to come).
  2. Our users do everything in Excel, meaning that much of the data entry UI for this app needs to be as Excel-ish as possible, including the dreaded Multi-Add (adding multiple rows between saves) and Multi-Edit (editing multiple rows between saves).  [FYI: It turns out that none(?) of the OTC Grids are actually designed for this.  You can make it work with Telerik if you want to try hard.  See postings like this one in Telerik’s forums for more info.  They have come a long way since that posting.]
  3. Management is opposed to fat client or virtualization, so the app has to be web-based.
  4. After much trial-and-error, and trial-and-failure, and trial-and-compromise, we deployed an ASP/Ajax solution that was less than satisfactory and not-at-all Excel-ish, so we had to find a “better way”.
  5. We have a code base that comprises 8 years of work in VB 6, classic ASP, ASP.Net 1, ASP.Net 2, ASP.Net 3.5, VB.Net (all sorts), Infragistics (an old version), Telerik (several versions), copious quantities of javascript, several generations of CSS and DHTML, including many of the really exotic first generation tricks, Ajaxified ASP pages, ASP/Ajax pages and an Oracle back-end, so we knew that ASP was not going to give us what we needed.
  6. None of us had ANY desire to explore Flex.
  7. We are a Microsoft shop, so building a Java app was not really an option.
  8. Silverlight 3 was coming and promised enough features for us to begin writing an Enterprise app.  (It turns out that we jumped the gun on this, but we were not alone and SL4 promises to remedy many of the “it’s-not-ready-for-the-enterprise” issues.)

We are using DevForce and the Entity Framework because:

  1. Having worked with Hibernate, NHibernate, and SubSonic (which I preferred over NHibernate), I was convinced that a Data Layer / ORM would make our application specific code much easier to write and would provide more and better infrastructure/plumbing than we ever could.
  2. Having been told:  “No Open Source”  and given 3 weeks to pull SubSonic out of a working project and replace it with a roll-my-own ORM, I knew that many features we needed (Concurrency and caching, to name just two) were going to be a HUGE effort to write myself, and that if this was a Make or Buy decision, that Buy was clearly the better choice.  (Check out Davy Brion’s Build Your Own Data Access Layer Series for a deeper examination of the Make option.)
  3. Having been exposed to DevForce Classic a few years ago, I knew their product provided much of what we needed, and they were on the cusp of releasing a Silverlight version of their WPF framework.  As an added bonus, their documentation, and Ward Bell’s blog, are highly readable and provide excellent project guidance and design philosophy.
  4. DevForce sits on top of Entity Framework, which does not support Oracle, but as this was about to kill the deal, we found that DevArt’s Oracle drivers were finally supporting EF properly.

We are using Prism and Unity because:

  1. If you’re gonna do this thing, you might as well go all in.
  2. Having worked with CAB for a Windows App, I understood the potential of a component based application framework — or at least imagined I understood it, can anyone really understand anything PnP publishes?
  3. After dabbling in the Java world for a few months, I had developed an appreciation for Spring, Dependency Injection, configuration over coding and convention over configuration.
  4. I am unrepentant about preferring Agile development practices, and many of the “best practices” prescribed by PnP and implemented in Prism, represent many Agile coding principles in action.  Both VersionOne and RallyDev have Agile 101 documentation on-line.   Mike Cohn has written several excellent books introducing teams to Agile practices.

So we ended up with the following technology stack:

  1. Prism 2 for its Modular framework
  2. Unity for Dependency Injection
  3. Microsoft Silverlight 3 for the UI
  4. Telerik for Silverlight for several of its UI components (alas, we still have to do far too much ourselves in this area though)
  5. IdeaBlade DevForce for Silverlight for its Silverlight friendly Business Entity model and asynchronous client-server communication layer
  6. DevArt dotConnect for Oracle drivers for its support of the MS Entity Framework and it’s excellent Entity Developer tool
  7. Microsoft Entity Framework for the server-side Entity Model and database connectivity

Mysteries of Silverlight Deployment – Error Code 2104 – Could not download the Silverlight application

So I’m trying to open a newly deployed Silverlight site/app in my browser.  I have the latest version of Silverlight, the files are deployed, the security is configured.  Still, one of my Silverlight apps is downloading to the browser properly, the other one, gives me the following error:

Error: Unhandled Error in Silverlight Application
Code:  2104
Category: InitializeError
Message:  Could not download the Silverlight application.  Check web server settings

I checked the web.config.  Nothing different between the site that works and the one that doesn’t.

I checked a bunch of other things.  Nada.

I finally broke down and started a tab-by-tab comparison of the Web Site Properties dialog in IIS Manager.  (IIS 6.0)  On the HTTP Headers tab, everything matched.  Then I clicked on the MIME Types… button, and there was my discrepancy.

In order for IIS 6 to serve up a Silverlight App, you have to add the following MIME Types to the Web App Properties, HTTP Headers tab:

.xaml application/xaml+xml
.xap application/x-silverlight-app
.xbap application/x-ms-xbap

After adding these entries, I had to click OK a couple of times to get back to IIS Manager and save the change.  Then I had to close and re-open my browser because IE likes to cache everything so even a refresh didn’t download the Silverlight app.  Once I re-opened, the Silverlight app loaded, and I was back to debugging.  Yay.

Opening Salvo: Planning your SCM for a Silverlight project

One of the easiest decisions to make when embarking on a Silverlight development adventure, is to decide to use a Source Code Manager (SCM) to keep the myriad projects and files organized.

I shall leave it up to you to decide which SCM to use.

As far as setting up the SCM environment, there are treatises elsewhere (I hope) on the philosophical disagreement on setting up releases, branches and code progression paths in SCM.

As for me and my house, we have standardized on a very small implementation of SCM philosophy.

First, with regard to promotion and versions:

  1. The Production code is the Top level Branch.
  2. Below that is the Staging code (for us, Staging is where real users do testing).
  3. Below Staging is the QA code (QA is where certain  designated project testers do testing).
  4. Below QA is the Dev code (Dev represents the latest version of the code that has been promoted from each of the developers.  This is used for integration and unit testing, and is the place where developers test their contributions after they have finished their local coding/testing effort.  There is an automated build process that builds, tests and deploys (if build is successful) the compiled project to the Dev server for integration testing.
  5. Below the Dev code are the individual workspaces for each developer.  Each developer can create workspaces off the Dev branch.  They are free to make their changes in their workspaces, and their changes are isolated from:
    a) the integration build on the Dev server;
    b) other developer’s “work in process”; and
    c) their own experiments and “not for this release” changes.
  6. Code is promoted from each developer’s workspace to the main Dev branch.  It is then occasionally promoted from the Dev branch to QA for testing.  When it passes it is promoted to Staging for testing.  When that passes the code is promoted to Production on the release schedule.For example:
    SCM Example

Second, with regard to tools and dependencies:

  1. In the DV branch, there is a folder called Installations, where we keep the installers for all of the tools we use.  This serves two purposes: a) it centralizes the installs so rebuilding a dev environment is not such a chore; b) it makes sure that all the dev environments are using the same versions of the same tools.  We have also checked in a readme.txt for each tool documenting our licenses, download locations, vendor logins, etc., needed to obtain the file from its source or to get updates.  This folder is then “cloaked” in our SCM to ensure that it is not promoted up to the QA branch.  Developers can cloak it in their branch once they have installed everything and configured their environment so that they can delete the install files and reclaim that space.

    Installations Folder example

  2. In the DV branch there is a folder called Dependencies, where we keep all the DLL’s and third party references.  All projects in the solution(s) then reference the DLL’s from the Dependencies folder, and NOT from their local Program Files installation of the tool in question.  This serves two purposes:  a) it ensures that, regardless of which version of which tool is installed locally, that all of the DLL’s required to compile the app are in SCM and are in a folder that has the same relative path (i.e. ..\dependencies) on every developer’s hard drive.   This avoids so many seemingly random errors that crop up when a developer links a project to their own Program Files menu.  NOTE:  This pretty much invalidates the use of “Add Reference, Select from List” for all but the core MS DLL’s, as you will almost always have to pick “Add Reference, Browse” to get the reference to point to the Dependencies folder.  It also means that most project creation wizards will produce a project that you then have to remove and recreate the references in so that they point to the Dependencies folder that the wizard knew nothing about.In our projects, DLL’s from: C:\Program Files\Reference Assemblies and C:\WINDOWS\Microsoft.NET, are referenced from those locations, all other DLL’s are referenced from the copies stored in the Dependencies folder.  For example, the C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries folders are copied over to the Dependencies\Silverlight\Libraries folder.

    Dependencies Folder example.