Development Diary


 


Web 2.0 Goodness!



Wow, look at me entering the new web dawn already!

I've finally implemented some Web 2.0 goodness, there's now some tagging on this site - go check out the Albums if you don't believe me ;), clearly I've not finished tagging everything - and Zach's name is going to be the biggest thing on the page by the time I've finished - he's in nearly every picture we've taken since December 2004!

However, like the blogs, they aren't truely web 2.0, as they aren't user generated, but then, that's what our SEO guys tell us to do as well...

On top of that, it's all been powered up with Linq to Sql goodness, more posts on my trials and tribulations with that to follow (things like Enumerating over your results from Stored Procs; How to get a single entity from a Linq Query; etc) - in case you hadn't noticed, the albums are based (loosely now) on the Album Component of the Personal Web Site Starter Kit - there was so much dubious code in there (that's still in the recently updated, Linqified one) that I've cleaned out - not closing the files it's opened from the file system etc - I thought these were supposed to be "Best Practice Showcases" as well as "Hey, look what you can do" type things?

I've also got to get back to the MCMS and .Net 3.5 series now the site has finally launched - I also need to add to that a post on How to get MCMS development started under Visual Studio 2008.

Clearly, I'm going to be busy...



Posted: 01:02, 02/05/2008 by zhaph

MCMS, Master Pages and Nested Master Pages



Obviously, there’s no problem with using Master Pages with MCMS SP2, so there’s a big win right there, however now that Visual Studio 2008 supports Nested Master Pages we’re on a real roll.

We’ve defined a number of shared placeholders (e.g. page title, browser title, keywords, meta description, etc) that all templates should have, and most of these are metadata fields – more on this in a minute.

So first of all we build a base master page with all the basic page layout – headers, left hand navigation, footers, standard CSS classes, MCMS Console, and then build up some additional master pages to layout the pages further – for example one with one main content column and one with two main content columns.

We can then build our pages on these child master pages, but still have all the layout of the base master defined in one place.

The MCMS placeholders can obviously exist quite happily on any of these controls (page, specific master page or base master page, or indeed on a user control).

You remember that I said a lot of the shared placeholders where metadata? And clearly when the author is editing the page they need to be able to see the controls for them, but in presentation mode these controls need to render out in the page’s metadata elements. So how did we go about this? Simple: Create a class that inherits from System.Web.UI.Page, and change our pages to inherit from this “BasePage” instead. Then, we can override the OnPreInit event and do the following:
if (CurrentUserIsAuthoring())
{
    Page.Master.MasterPageFile = "/MasterPages/BaseAuthoring.Master";
}
base.OnPreInit(e);
So we pick up the page’s Master, and then change the Master Page file of that to our Base Authoring master page instead of the Base Presentation master page. This also allows us to completely change the display and style of the page in Authoring mode as well – something the client is quite keen on.



Part of the Series: The joys of using .Net 2.0, .Net 3.0 and .Net 3.5 with MCMS

Posted: 16:50, 25/01/2008 by zhaph

The joys of using .Net 2.0, .Net 3.0 and .Net 3.5 with MCMS



Well, I suppose I’d best admit it – otherwise there’ll be no more blog posts for a while. The current project I’m working on is still in MCMS – an issue with the clients deadline and us get the team up to speed with MOSS really – however we are using the latest versions of the framework – so that means ASP.NET 2.0 on the server, and taking advantage of the features in .Net 3.5 where appropriate.

The main things we’re using so far are:
(Seeing as the first item on that list has been sitting on my hard drive for about two weeks now, I guess this is going to be an instalments piece - I’ll update the list with links as things are posted)

Posted: 16:45, 25/01/2008 by zhaph

LINQ to SQL: Changes since Beta 2



So, Visual Studio 2008 is now in RTM, which also means that LINQ has moved out of Beta. Yay.

However, I've found some breaking changes between the Beta 2 and RTM bits:

  1. Table<T> no longer has a method Remove() - this has been renamed to DeleteOnSubmit(). This apparently is to "better convey that the updates are deferred until the call to DataContext.SubmitChanges()" (MSDN Forums)
  2. The XML declaration of the .DBML file has changed, in Beta 2 this was:
    <?xml version="1.0" encoding="utf-16"?>
    In the RTM this has changed to:
    <?xml version="1.0" encoding="utf-8"?>
    Curiously, this UTF-16 caused VS to complain about unicode support, and wouldn't open the design surface. Changing it to UTF-8 fixed the issue.
I'll post more as I find them.

Posted: 10:29, 30/11/2007 by zhaph

LINQ to SQL for Windows Forms Revisited



Well, finally, we get some guidence on the DataSources for LINQ in Windows Forms applications.

This seems better than my hack of editing the generated partial class that I posted about in September (Playing with LINQ For SQL in a Windows Forms Application).

Posted: 17:20, 02/11/2007 by zhaph

Samuel's First Pictures



As promised yesterday, the pictures are now online, and can be found here:

Samuel William's First Day

Posted: 13:20, 19/10/2007 by zhaph

Samuel William Duguid



And there was much rejoicing! Samuel William was born at 21:35 on 17 October 2007, weighing 7lbs 10oz. Mother and baby doing well, pictures to follow - I'm off to bed.

Posted: 01:35, 18/10/2007 by zhaph

This is a test



This is a test, please ignore it.

Basically, we should now have pingback functionality here, and to prove it, here's a link I made earlier:
Facebook Blog Import

Posted: 22:50, 16/10/2007 by zhaph

Playing with LINQ For SQL in a Windows Forms Application



Don’t look now, but I think this might actually be a technical posting!

So, I’ve finally had an excuse to start playing around with LINQ – some data clean up tasks that I could have done by hand, but it’s always more fun to throw together a little app or two than spend your life in Enterprise Manager (or SQL Studio).

The key issues I came up against were with DataGrids, and picking and populating columns.

A fairly simple setup for editing the Taxonomy (remember, this is a developer application, so it works for me):
Editing the taxonomy
 
We have a ComboBox providing the Category, and then the DataGrid allows us to edit the Subjects. The “Subject ID” is an auto-generated GUID that is occasionally useful for the developer to know, so I wanted to display it, the data model looks like this:
The database schema
 
As you can see there’s an additional column in the database that I’m not interested in for the DataGrid: “TAX_CATEGORY_ID” this is always powered by the Category selected in the combo box, so I didn’t want to have to set it every time.

Part 1: Designer Support for LINQ Database Models (DataContext)



When wiring up the DataGrid, I initially tried the following:
editSubjects.DataSource = from ts in db.TaxonomySubjects
where ts.TAX_CATEGORY_ID == (Guid)chooseCategory.SelectedValue
orderby ts.SORT_ORDER
select new { ts.TAX_SUBJECT_ID, ts.SORT_ORDER, ts.DISPLAY_NAME, ts.METADATA_NAME };
This almost worked – I had the columns I wanted, but I couldn’t edit the values at all – it turns out that if you use an anonymous type you lose the ability to edit it – the DataSource doesn’t know how to safely update the object, so disables editing.

On top of that, you have no way to change the column properties of the DataGrid in the designer.

I’d read about the ASP.Net LinqDataSource control, and so (naively) assumed there’d be a similar one for WinForms, but apparently not, and after hunting around and reading the readme of the samples that come with VS 2008 (namely the WinFormsDataBinding sample), I found the follow “solution”:

  1. Add a BindingSource to your form
  2. In the .Designer.cs class, add the following in the InitializeComponent() method:
    this.taxonomySubjectsBinding.DataSource = typeof(MetadataManager.TaxonomySubject);
    Replacing the binding name with your binding name, and the value in typeof() with the value from your “Linq To Sql” classes
  3. You can now assign that BindingSource to your DataGrid and get access to the column builder:
    Editing columns
    As you can just about see, the DataGrid doesn’t display the TAX_CATEGORY_ID column although it is there, and I’ve been able to supply nice names for the columns.
My data source wire up now looks like this:
editSubjects.DataSource = from ts in db.TaxonomySubjects
where ts.TAX_CATEGORY_ID == (Guid)chooseCategory.SelectedValue
orderby ts.SORT_ORDER
select ts
Which is just taking all the TaxonomySubject objects that match the query, and the DataSource is then filtering their properties into the correct columns without me having to worry about anything else.

Part 2: Populating hidden columns/Auto Generated Ids in Linq DataContexts



Having successfully cleaned up my DataGrid columns, I now had two remaining problems to solve around adding a new record:
  1. Generating the new GUID for the subject.
  2. Adding the TAX_CATEGORY_ID value to the hidden column.
In the database, the TAX_SUBJECT_ID field is defined as:
[TAX_SUBJECT_ID] [uniqueidentifier] NOT NULL   CONSTRAINT [DF_TAX_SUBJECTS_TAX_SUBJ_ID]
DEFAULT (newid()),
So, it’s the primary key column, with a default value of a new GUID. This is where our problems begin.

LINQ understands that SQL can auto-generate the values for columns on a database, provided:
Primary keys that are designated IsDbGenerated=true should also have a DBType with the IDENTITY modifier.
Note that my column here is not marked as an Identity column – to use the IsDbGenerated property, anything that goes in that column must be an integer.

I noticed that my DataContext class contained the following methods in a region called “Extensibility Method Definitions”:
partial void InsertTaxonomyCategory(TaxonomyCategory instance);
partial void UpdateTaxonomyCategory(TaxonomyCategory instance);
partial void DeleteTaxonomyCategory(TaxonomyCategory instance);
partial void InsertTaxonomySubject(TaxonomySubject instance);
partial void UpdateTaxonomySubject(TaxonomySubject instance);
partial void DeleteTaxonomySubject(TaxonomySubject instance);
So, let’s implement an insert in a new class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MetadataManager
{
public partial class MetadataDatabaseDataContext { partial void InsertTaxonomySubject(TaxonomySubject instance)
{
if (Guid.Empty == instance.TAX_SUBJECT_ID)
instance.TAX_SUBJECT_ID = Guid.NewGuid();

this.ExecuteDynamicInsert(instance);
}
}
}
A really key thing to note here – if you create these methods, even as empty methods, you must call this.ExecuteDynamicInsert(instance); otherwise any changes you try to submit will be lost.

Basically, before the changes are inserted into the database, this method fires for each one, and I’m creating a new GUID if the column is empty.

When adding just one new row this seems to work ok, but as soon as I try and add more rows, or two at a time, I get exceptions like:
"Cannot add an entity with a key that is already in use."
Hardly ideal – the key’s not in use, but I guess there’s something else I’m missing – any thoughts? On top of that, there’s no way to insert the Category ID into the foreign key column in this method.

So the final solution I came up with to resolve this was to hook into the RowEntered event on the DataGrid:
private void editSubjects_RowEnter(object sender, DataGridViewCellEventArgs e)
{
int rowIndex = e.RowIndex;
if (null == editSubjects["taxSubjectId", rowIndex].Value)
{
editSubjects["taxSubjectId", rowIndex].Value = Guid.NewGuid();
}
if (null == editSubjects["taxCategoryId", rowIndex].Value)
{
editSubjects["taxCategoryId", rowIndex].Value = (Guid)chooseCategory.SelectedValue;
}
}
This lets me generate a new GUID for the row, and adds the Category’s ID to the hidden column.

Which feels to me like an awful cludgy hack (but then so does a lot of the LINQ stuff as well – it’s all inline SQL really isn’t it? Isn’t that supposed to be bad?), but then I read the rest of ScottGu’s blog post – to get a custom query hooked up to a LinqDataSource you have to hook into the Selecting event and replace the result property with your new query…

Any thoughts, let me know.

Posted: 14:45, 18/09/2007 by zhaph

Facebook blog import



Well, as many other people have pointed out, you can import your blog into facebook as notes - it's quite clever an puts them all in the right place based on date.

Last time I tried this, I ended up with duplicate notes when I wrote a new blog post, so this is mostly to prove that it does that, or that something's changed and facebook no longer duplicates them.

I think it might be something to do with the fact that I'm not using a permalink as the posting guid, but the id (GUID) of the posting in the database, but who knows.

Anyone else having the same problem? Let me know.

Posted: 20:17, 07/09/2007 by zhaph