Notes on upgrading to Office 2010

Posted 04 June 2010, 17:22 | by | | Perma-link

This is one of those "20/20 hindsight is a wonderful thing" posts.

The basic issue is that Visio and Project aren't really part of Office, and should probably be uninstalled before you upgrade the main Office Suite - don't rely on their installers to properly clean them out.

I didn't do this, and had the following symptoms floating around:

Visio 2007 and Project 2007 were both still listed in my All Programs menu, with a tool tip "Installs on first use".

I imagine that at somepoint after upgrading Visio 2007 to 2010, I typed Visio<enter> into my start menu, and Visio 2007 reinstalled itself. I then opened Visio 2010, and that reconfigured itself through an installer. I uninstalled Visio 2007 again from the "Programs and Features" control panel, deleted the links, and the files in C:\Windows\Installers\ that they were pointing at.

I thought I was happy - turns out I was wrong. I was working in SharePoint, and getting these odd javascript library not registered errors:

Message: Library not registered.
Line: 1935
Char: 4
Code: 0
URI: http://server/_layouts/1033/init.js?rev=ck%2BHdHQ8ABQHif7kr%2Bj7iQ%3D%3D

Running the Repair tool (Programs and Features, Office 2010, Change and select "Repair") and restarting my machine seems to have fixed the issue nicely.

I hope this helps somebody else, and saves them the hour or so of confusion it's caused me.

Filed under: Fixes

Playing with Seesmic Desktop

Posted 05 May 2010, 17:16 | by | | Perma-link

Update: There's now a "How-To" guide to Doodle Grouper 28/11/2011

Update: I've uploaded a newer version, for more details see: Doodle Grouper 1.0.0.3 Released 05/04/2011

Update: I've uploaded a newer version, for more details see: Further work on Seesmic Desktop 05/07/2010


Doodle Grouper LogoI've just spent a couple of evenings playing around with the Seesmic Developer Platform - an early release of their Silverlight 4 based, out-of-browser Social Media Client Seesmic Desktop.

In terms of history, I'd started with the Adobe Air based Seesmic Desktop, moved to Seesmic for Windows as soon as it was announced, and missed some of the features, but none of the resource hogging of the Air version.

The latest version of Seesmic Desktop seems like it will be able to address many of my issues - and if it doesn't, well, then it's built with extensibility in mind - the Seesmic team have taken one of the key additions to Silverlight to heart - Seesmic Desktop 2 uses the Managed Extensibility Framework, or MEF, to enable developers to easily create plugins.

With that in mind, here's the beginnings of the fruits of my labours - a plug-in for Seesmic Desktop that allows you to group users into columns that auto-update as new tweets/updates come in - yes, I know, the previous versions can all do this, and I'm sure the Seesmic guys will add it soon enough, but I always find that having a goal in mind drives me to learn about stuff more than just hacking around with no real direction.

This is currently version 0.0.1 - so it's very raw around the edges:

  • I need to work out how to pick up the parent's themes correctly (the buttons are nicely themed, but the forms aren't.
  • There's no way through the UI to remove a user from a group.
  • There's no way through the UI to remove a group.

Certainly the last two will be resolved fairly shortly Wink

You can download:

  • The source - you'll need to update the references to the Seesmic.Sdp.* libraries.
  • The compiled plugin - Save to Documents\Seesmic\Seesmic Desktop 2\Plugins

Thanks go out to Tim Heuer for his Seesmic Developer Templates.

As a basic overview, this project uses:

  • A global TimelineItemAction to allow the user to add someone to a group.
  • A TimelineItemProcessor to deliver items to the correct timelines/columns/groups.
  • SidebarActions to provide access to each group.
  • The StorageService to save group information.
  • The LogService to write rather a lot of information to the logs - I assume at some point we'll be able to say "don't write out Info level logging" or some such, but while we're all debugging this is invaluable.

The log file can be found in Documents\Seesmic\Seesmic Desktop 2\Logs and you get quite a bit of detail about loading, etc for free.

As ever, let me know how you get on, or come and join us all making it better.

Filed under: Plug-ins, Seesmic, Silverlight

Implementing Flickr.Net

Posted 26 April 2010, 15:27 | by | | Perma-link

Flickr.NET is a ".NET library for accessing the Flickr API". It's hosted on CodePlex, and (thankfully for me) updated to version 3.0 Beta just before I downloaded it.

I host all my images here on the site, provide RSS feeds of both the latest photos and each album, however beyond using a service like twitterfeed I'd not found a nice way to integrate it into other social networks - Facebook can only accept one blog feed directly and while Google Buzz picked up on the blog feed through the "Connected Sites" options (I guess through the WebMaster tools association) it only seems to accept the first feed it finds, so I thought if I post the images to Flickr as well, then there would be more integration for them.

So, after spending a little time nosing around the Flickr API docs, I went off and got the latest version of Flickr.NET, dropped it in my projects /bin folder, and added a reference to it.

The next step was to request an API key from Flickr - you'll want a different key for each application you produce as the query limits are per key - and then set up the application - you need to give it a description, pick your application type (Desktop, Web or Mobile) and then define how you're handling authentication, for a web application this means supplying a callback url - while testing http://localhost/ addresses (with port numbers if required) worked fine.

Flickr.NET comes with it's own configuration section that you could use to set up Flickr.NET:

<flickrNet apiKey="APIKEY" secret="SHAREDSECRET" cacheDisabled="true">

Which then allows you to call the library as:

var flickr = new FlickrNet.Flickr();

However, I found that this didn't play nicely in a Medium Trust environment (the main disadvantage of shared hosting), as the constructor threw an exception complaining that the it couldn't write to the cache location (even though it's configured to be disabled) - I'll admit now that I didn't look too hard into diagnosing this issue - I'm only submitting images, rather than downloading them, so I didn't feel much need for caching.

So I pulled the API Key and Shared Secret out into the main appSettings settings, and factored out the constructor into a simple factory class:

public class FlickrControl
{
  internal static Flickr GetFlickr() {
    // Disable Cache before calling anything else
    Flickr.CacheDisabled = true;

    // Create Flickr instance with simple constructor.
    var flickr = new Flickr(WebConfigurationManager.AppSettings["FlickrApi"],
                            WebConfigurationManager.AppSettings["FlickrSecret"]);

    return flickr;
  }
}

I then created two new controllers - one to handle the initial login request, and one to handle the response back from Flickr:

// User wants to authenticate with Flickr
public ActionResult Flickr() {
  // Store calling page in session to return the user to later
  Session["Referrer"] = null != Request.UrlReferrer ?
                       Request.UrlReferrer.PathAndQuery : string.Empty;

  // Get an instance of Flickr
  var flickr = FlickrControl.GetFlickr();

  // Redirect the user to Flickr authentication service
  // asking for Delete priviledges (so we can remove images).
  return new RedirectResult(flickr.AuthCalcWebUrl(AuthLevel.Delete));
}

// Flickr is returning a logged in user
public ActionResult FlickrReturn(string frob) {
  var flickr = FlickrControl.GetFlickr();

  // Generate an Auth Token from the "frob" returned from Flickr
  var auth = flickr.AuthGetToken(frob);

  // Store the authentication token for later use
  // ExternalSites.FlickrAuth is a static string value for finding this object.
  Session[ExternalSites.FlickrAuth] = auth;

  // See if we can find the users previous request to return them to.
  var referrer = Session["Referrer"] as string;

  if (!string.IsNullOrEmpty(referrer)) {
    // We found their previous page, bounce them back
    return new RedirectResult(referrer);
  }

  return RedirectToAction("Index");
}

Then when a user uploads, edits or deletes an image from the site, we check to see if they are authenticated with Flickr, and perform the same action on Flickr:

// Inside the Upload action
// Check to see if the user is Authenticated, and that they want to upload the image
if (null != Session[ExternalSites.FlickrAuth] && editPhoto.UploadToExternal) {
  var auth = Session[ExternalSites.FlickrAuth] as Auth;

  if (auth != null) {
    var flickr = FlickrControl.GetFlickr();
    // Add the user's auth token to our Flickr instance
    flickr.AuthToken = auth.Token;

    // See below
    FlickrControl.UploadImage(photo, flickr, ImageData.FileName);

    // Upload image adds the Flickr id to the photo, so we need to save
    // that to the image as well.
    m_PhotoRepository.Save();
  }
}

This is the method for uploading an image:

internal static void UploadImage(DoodlePhoto photo, Flickr flickr, string fileName) {
  if (null == photo.PhotoDetail) {
    // If editing a photo, the image won't be in memory, so needs to be loaded.
    photo.PhotoDetailReference.Load();
  }

  if (null == photo.Album) {
    // If editing a photo, the Album info won't be in memory, so needs to be loaded.
    photo.AlbumReference.Load();
  }

  // UploadPicture returns the id of the image on Flickr
  photo.FlickrId = flickr.UploadPicture(
              // Raw stream of image bytes
              new MemoryStream(photo.PhotoDetail.BytesOriginal.ToArray()),
              // might as well pass in string.Empty here,
              // not really needed as we're passing in a stream
              fileName,
              // The title that's displayed in Flickr
              photo.Caption,
              // The description that appears under the image in Flickr
              photo.Description,
              // The tag list
              photo.CollapsedTags,
              // Set the permissions on the Album - if it's public,
              // whether Family or Friends can see it.
              photo.Album.IsPublic, true, true,
              // What type of image it is (they are effectively all photos).
              ContentType.Photo,
              // I'm not uploading anything inappropriate
              SafetyLevel.Safe,
              // What search level should be used
              photo.Album.IsPublic
                ? HiddenFromSearch.Visible
                : HiddenFromSearch.Hidden);

  // Once the image is uploaded, we need to add it to the a photo set as well.
  addPhotoToPhotoset(photo, flickr);
}

To update an existing image on Flickr I use the following method:

internal static void UpdateImage(DoodlePhoto photo, Flickr flickr) {
  // Update the metadata for an existing image
  flickr.PhotosSetMeta(photo.FlickrId, photo.Caption, photo.Description);
  // Replace all tags for an existing image
  flickr.PhotosSetTags(photo.FlickrId, photo.CollapsedTags);

  // Check to see if we've created this photoset already
  if (string.IsNullOrEmpty(photo.Album.FlickrPhotoSetId)) {
    // Photo set doesn't exist, therefore we can safetly add the image
    addPhotoToPhotoset(photo, flickr);
  } else {
    // Photoset already exists, so we need to check if the image is
    // not already in the photoset, and add it if needed
    if (!photoSetContainsPhoto(photo, flickr)) {
      addPhotoToPhotoset(photo, flickr);
    }
  }
}

To add a photo to a photoset:

private static void addPhotoToPhotoset(DoodlePhoto photo, Flickr flickr) {
  // Check to see if we've already created a photoset
  if (String.IsNullOrEmpty(photo.Album.FlickrPhotoSetId)) {
    // Create a new Photoset, with the Photo's FlickrId as the Primary Photo Id
    var photoset = flickr.PhotosetsCreate(photo.Album.Caption,
                                          photo.Album.Description,
                                          photo.FlickrId);

    // Store the Photoset Id with the Album.
    photo.Album.FlickrPhotoSetId = photoset.PhotosetId;
  } else {
    // Simply add the Photo to the Photoset.
    flickr.PhotosetsAddPhoto(photo.Album.FlickrPhotoSetId, photo.FlickrId);
  }
}

Finally, the code to check if a Photo already exists in a PhotoSet:

private static bool photoSetContainsPhoto(DoodlePhoto photo, Flickr flickr) {
  // Get the details of the photos in a Photoset, will become an issue
  // only when I add more than 500 images to a Photoset!
  var photos = flickr.PhotosetsGetPhotos(photo.Album.FlickrPhotoSetId);
  // Return true if the photo's Id appears in the list.
  return null != photos.SingleOrDefault(p => p.PhotoId == photo.FlickrId);
}

Deleting a photo from Flickr is a trivial exercise, simply requiring a call to PhotosDelete with the Flickr Id of the photo.

All in all, I found this to be very clean, and fairly intutive - especially if you take the time to read the API as you go.

Filed under: .Net, ASP.NET MVC, Site Updates

Implementing DataAnnotations

Posted 26 March 2010, 00:29 | by | | Perma-link

Update: As of Entity Framework 4.1, the MinLengthAttribute is no longer needed as it's now part of the framework, but the length is the second parameter in the string format argument list, with the field name in position {0}. 06/06/2011

As I hinted at in my post "Upgrading to ASP.NET MVC 2.0", one of the main remaining changes I wanted to make after upgrading to version 2.0 was to move to using the DataAnnotations that gained first class support.

I've now done this, which meant that I've removed all the code based on the Nerd Dinner validation patterns, and switched to using the Validation Attributes classes.

I started with the basic RequiredAttribute to ensure that all required fields had a value, but then wanted to do a bit more - on my Contact form for example wanted to ensure that the name supplied was at least 3 characters long, that the email address used my rather more rigorous regex than ScottGu's, and that the message was at least 10 characters long.

A simple answer was to use the RegularExpressionAttribute, with settings such as @".{3,}" for the minimum length, and the lengthy pattern for emails, however I wasn't happy with this for a number of reasons:

  1. I wanted to use the "minimum length" validator on multiple properties, with different minimum lengths but very similar error messages including details of the length.
  2. Because my email pattern is compiled using string.Format to make it more manageable, I can't use it in a attribute as it needs to be a "compile time constant".

I also wanted something similar to the IntegerValidator in the Configuration namespace that allows me to specify just a MinValue, rather than the Range Validator, where I needed to supply an arbitrary high value to meet my needs.

As I'm not yet using the .NET 4 framework, I don't have access to the CustomValidatorAttribute, that's no bad thing in my mind, as I'm not a big fan of the "Magic String" form of configuration that I would need to use.

To that end I've created three validators:

public class IsEmailAttribute : RegularExpressionAttribute
{}
public class MinValueAttribute : ValidationAttribute
{}
public class MinLengthAttribute : ValidationAttribute
{}

IsEmailAttribute just supplies the email pattern (built in a read only property) to the base constructor, while MinValueAttribute and MinLengthAttribute both implement the IsValid method, and override the FormatErrorMessage to enable me to include the set value of the validator.

The full code for the MinLengthAttribute is:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class MinLengthAttribute : ValidationAttribute
{
  public int MinLength { get; set; }

  public MinLengthAttribute(int minLength) {
    MinLength = minLength;
  }

  public override bool IsValid(object value) {
    bool isValid = false;

    var stringValue = value as string;

    if (null != stringValue
        && MinLength <= stringValue.Length) {
      isValid = true;
    }

    return isValid;
  }

  public override string FormatErrorMessage(string name){
    return string.Format(ErrorMessageString, MinLength, name);
  }
}

The one big problem I've had with doing it this way is that the automation of the client-side validation doesn't work, but as it doesn't plug into the Validation Summary area, this is no great loss, as I'd have to redesign my forms more than I'd like to implement that.

The other major change I had to make to my code was to move to more of a ViewModel pattern - on some of my admin screens I was taking a FormsCollection rather than an explicit model which allowed me to have a photo form with text boxes for Caption, Order and Tags (which holds a comma seperated list of tags), but this doesn't map nicely to the Photo model, where Tags is a collection of Tag models. Writing a ViewModel for editing photos, all the annotations wired up nicely, and gave me much better control of what was being sent to the view.

One thing that was needed uploading photos that I did need to do was handle the case of a user not including an image - thankfully, the previous code set me in good stead:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UploadPhoto(int id,
                                EditPhoto editPhoto,
                HttpPostedFileBase ImageData) {
  ViewData["Title"] = "Create Photo";
  ViewData["Message"] = "Upload a new photo";

  if (ModelState.IsValid
      && null != ImageData
      && ImageData.ContentLength != 0) {
    // Persist to database
    // Return appropriate view based on Request.IsAjaxRequest
  }

  if (null == ImageData || ImageData.ContentLength != 0) {
    // ImageData is missing
    ModelState.AddModelError("ImageData", "You must supply a photo.");
  }

  // Return appropriate view based on Request.IsAjaxRequest
}

So we can still add additional errors to the ModelState property, allowing us to highlight additional fields that aren't part of the ViewModel.

Where I haven't created a ViewModel, I've used the MetadataTypeAttribute on the partial classes created for the Entity Framework classes:

[MetadataType(typeof(AlbumMetadata))]
public partial class Album {
  public string Description {
    get {
      return string.Format(
        "Photos from the album \"{0}\" on http://www.doodle.co.uk/Albums.aspx/{1}/{2}",
        Caption, AlbumId, Caption.CreateSlug());
    }
  }
}

public class AlbumMetadata {
  [Required(ErrorMessage = "You must supply a caption that is at least 3 characters long.")]
  [MinLength(3, ErrorMessage = "The caption must be at least {0} characters long.")]
  public string Caption { get; set; }
}

Next time: Implementing FlickrNet.

Filed under: .Net, Entity Framework, Site Updates

Upgrading to ASP.NET MVC 2.0

Posted 17 March 2010, 19:46 | by | | Perma-link

As you might have seen, ASP.NET MVC 2.0 was released this week at MIX along with a handy tool to help upgrade your solutions, so I decided to take the plunge and see how much effort I'd need to go through to upgrade. It turns out not much.

I also managed to move my admin section off to an area, which meant I could finally have a URL structure that allowed me to have duplicate controllers for blogs and albums, which is something I'd wanted since I built them (as opposed to an AdminBlogs controller and an AdminAlbums controller, and it meant that the Tabs controller, used for autocomplete on the photo admin screens, could be nicely grouped with them as well).

The only outstanding piece of work now is to move to using Data Annotations for my form validation, which is where the bulk of the pain I'd encountered lay.

Basically, I'd taken a similar approach as the validation pattern in Nerd Dinner (pp. 37f): I'd created a view model that implemented the following IValidatable interface:

public interface IValidatable
{
  bool IsValid { get; }
  IEnumerable<RuleViolation> GetRuleViolations();
  void OnValidate();
}

I initially created an abstract BaseValidater class, but of course you can't have multiple inheritance in C#, so this only worked for my non-entity classes… The RuleViolation is identical to the Nerd Dinner one.

So for each View Model I created an enumerable Errors with yields for each possible error, for example (line breaks added to long strings for formatting):

public IEnumerable<RuleViolation> GetRuleViolations() {
  if (string.IsNullOrEmpty(PostTitle) || 3 > PostTitle.Trim().Length) {
    yield return new RuleViolation("The title is required.", "PostTitle");
  }

  if (3 > PostPath.Trim().Length || !PostPath.IsUrlPart()) {
    yield return new RuleViolation("The path is required, and should only " +
                        "contain alpha-numerics and hyphens.", "PostPath");
  }

  if (50 > PostBody.Trim().Length) {
    yield return new RuleViolation("The post body is required, and should " +
                        "be longer than 50 characters", "PostBody");
  }
}

And coupled this with the following implementation (tweaked from Nerd Dinner - I prefer using .Any() to .Count() as that only checks to see if there are any values, rather than enumerating over the entire set - not an issue for in memory objects like this, but something to consider with databases Wink):

public bool IsValid {
  get { return (!GetRuleViolations().Any()); }
}

Then in the controller I went with the following code to handle errors:

if (blog.IsValid)
{
  [...]
  return [...]
}

foreach (RuleViolation violation in photo.GetRuleViolations()) {
  ModelState.AddModelError(violation.PropertyName, violation.ErrorMessage);
  ModelState.SetModelValue(violation.PropertyName,
             new ValueProviderResult(
                   ValueProvider[violation.PropertyName].AttemptedValue,
                   collection[violation.PropertyName],
                   System.Globalization.CultureInfo.CurrentCulture));
}

The ValueProvider in 1.0 was an IDictionary but this has changed in 2.0 to be an IValueProvider, which means that you can't just iterate through without knowing what the form items were called (which I wasn't, but others are) so my code changed to:

foreach (RuleViolation violation in photo.GetRuleViolations()) {
  ModelState.AddModelError(violation.PropertyName, violation.ErrorMessage);
  ModelState.SetModelValue(violation.PropertyName,
           new ValueProviderResult(
                 ValueProvider.GetValue(violation.PropertyName).AttemptedValue,
                 collection[violation.PropertyName],
                 System.Globalization.CultureInfo.CurrentCulture));
}

The only other issue I had was how this was all going to play on IIS 6, but that turned out to be very easy in the RegisterArea method:

public override void RegisterArea(AreaRegistrationContext context) {
  context.MapRoute(
        "Admin_default",
        "Admin.aspx/{controller}/{action}/{id}",
        new { action = "Index", id = UrlParameter.Optional }
  );
}

All in all, very easy and smooth.

Filed under: ASP.NET MVC, Site Updates

In other news

Posted 01 March 2010, 22:02 | by | | Perma-link

A couple of updates on stuff:

  1. Just before Christmas I launched a new website for our church: Holy Trinity Beckenham (let's say it was a "soft launch" Wink). This was built using the amazing N2 CMS, which gave me everything I was looking for in a content management system, running in ASP.NET MVC, without me having to build the bulk of it - I'll do some posts in the future on the tweaks I made to it.
  2. You should now be able to subscribe to the latest blogs and (the new/re-instated) latest photos feeds directly from the homepage of this site. The latest photos can also be found on the albums page, and each album now has it's own latest photos feed as well.

I've also realised that I only mentioned half of the solution to a problem in my last post on moving from Linq to SQL to Entity Framework - namely how I solved the lazy loading of properties - it's there in the picture, but I haven't spelt it out, so there's another post coming on that.

Filed under: Websites

Moving from LINQ to SQL to the Entity Framework

Posted 02 February 2010, 00:50 | by | | Perma-link

As I said in my last post, I've rebuilt the site using ASP.NET MVC - other view engines are available, might be better, or at least better suited to your ideology, but this was the impetus I needed to actually start looking beyond the realm of Webforms.

The other main shift was from LINQ to SQL to using the Entity Framework (LINQ to Entities) as the data layer - once again, other ORMs are available, and don't have the baggage associated with being produced by Microsoft, but they also don't have the visual tooling - and while this site is primarily a place for me to play with cool new shiny toys, I do have a life, and more importantly a family, and didn't have all the time to learn how to configure them correctly or use them.

What I'm going to talk about today is my experiences moving from LINQ to SQL, some of the reasons behind why I moved, the benefits I saw, and the pain points I encountered - and to be honest, from what I've seen at the last two Tech.Eds, and read online, it looks like a lot of those pain points have been removed - although I'm sure there will a future post where I go over the "issues" I've encountered when upgrading Wink

One of the key things that I disliked about LINQ to SQL was the fact that there was an absolute mapping between the tables in your database, and the classes in your model:

Showing the relationship between Album, Photo, Tag, and TagsPhoto tables

This is an image from my LINQ to SQL DBML file, and it looks exactly the same as the ERD that I'd see in SQL Management Studio's diagram of the database - finding the text for all the tags for a given image required code such as:

For each (var tag in photo.siteContent_TagsPhoto.siteContent_Tags) {
  tag.Text;
}

Which (regardless of the naming convention) was painful, and unpleasant, so what I ended up doing was creating a set of helper objects, with sensible names, that had the right collection of properties on them, including a list of tags, that I would then use as:

public static List<Photo> GetPhotos(int AlbumID) {
  var zhpCtx = new ZhaphCoreContentDataContext([...]);

  bool? filter = !(HttpContext.Current.User.IsInRole("Editors") ||
                   HttpContext.Current.User.IsInRole("SiteAdmin"));

  var photos = from p in zhpCtx.siteContent_Photos
               join a in zhpCtx.siteContent_Albums on p.AlbumID equals a.AlbumID
               where p.AlbumID == AlbumID && (a.IsPublic == filter || a.IsPublic)
               orderby p.PhotoID descending
               select new {p.PhotoID, p.AlbumID, p.Caption};

  var results = new List<Photo>(photos.Count());

  foreach (var photo in photos) {
    results.Add(new Photo(photo.PhotoID,
                          photo.AlbumID,
                          photo.Caption,
                          GetTags(photo.PhotoID, zhpCtx)));
  }

  return results;
}

private static List<string> GetTags(int photoID,
                                    ZhaphCoreContentDataContext zhpCtx) {
  return (from tp in zhpCtx.siteContent_TagsPhotos
          join t in zhpCtx.siteContent_Tags on tp.TagID equals t.TagID
          where tp.PhotoID == photoID
          select t.TagText).ToList();
}

There are some nice things in there - I can easily select just the elements from siteContent_Photos that I want - so I'm not pulling back the actual image data from the photo objects when I don't need it, however I've had to jump through all those hoops to get the text of the tags into the results list.

So what did I end up with Entity Framework?

Entity Framework tables, showing Photos, Albums and Tags

Notice that I've lost the object representing the mapping table between Photos and Tags - great! I can now go directly from a Photo to its Tags, and from a Tag to the Photos.

BUT, this wasn't without its issues.

There were two main issues I had with Entity Framework version 1:

  1. I was unable to lazy load properties in Entity Framework as I had done in LINQ to SQL
  2. It was a lot harder to filter on complex CLR entities in Entity Framework than it was in LINQ to SQL.

Taking those points in greater detail then.

Lazy Loading Properties

As I showed above, I was able to easily select just those properties from an object that I wanted to load, projecting them out into a new class:

var photos = from p in zhpCtx.siteContent_Photos
             [...]
             select new {p.PhotoID, p.AlbumID, p.Caption};

So photos contains a set of implicitly typed objects, that have three properties: PhotoID, AlbumID and Caption - this is effectively the same as using the following SQL statement:

SELECT [t0].[PhotoID], [t0].[AlbumID], [t0].[Caption]
FROM [siteContent_Photos] AS [t0]

All that is retrieved from the database then is those three columns.

In Entity Framework I would say (method name has changed, but the result was the same, an object with a number of photos in it):

public Album GetAlbum(int albumId, bool loadPhotos) {
  ObjectQuery<Album> albums = loadPhotos ?
                       m_DoodleContent.Albums.Include("Photos").Include("Photos.Tags") :
                       m_DoodleContent.Albums;

  return albums.FirstOrDefault(a => a.AlbumId == albumId);
}

Which ended up loading all the content for each photo in the album - the reason I had to do it this way was that Entity Framework doesn't expose the AlbumID property of the Photo object either - so there was no way to say "give me all the photos with an AlbumID equal to x" as I had done in LINQ to SQL.

This also shows one futher issue that I've not fully resolved - as the TagsPhoto table is hidden from my object model, I can't query directly into that to build up the Tag Cloud that I had previously - were I'd been able to perform a GROUP in the SQL and get the COUNT of the tag ids from the TagsPhotos table, and then find the TagText for each tag.

Filtering on complex CLR types

Now, I've read a few explainations of why this behaviour exists, but none of them really convinced me fully.

In LINQ to SQL I could write the following, basically saying "get a blog post where the path (after the date) is equal to "path", and the Date the post was published on is equal to the date part of "publishedDate"":

BlogPosts post = (from blogs in blogPosts 
                  where blogs.PostPath == path &&
                        blogs.Published.Date == publishedDate.Date
                  select blogs).SingleOrDefault();

However, that wouldn't work with Entity Framework - changing "SingleOrDefault" to "FirstOrDefault" allowed it to compile, but the site would throw nasty exceptions at runtime, along the lines of "System.NotSupportedException: The specified type member 'Date' is not supported in LINQ to Entities".

I initially worked around this by searching for all posts with a given path, calling ToList() on the collection, and then searching that for date, but I didn't like that either, as it (obviously) loaded all the potentially matching blogs before it found just the one I wanted.

What finally worked for me was:

BlogPost post = (from blogs in blogPosts
                 where blogs.PostPath == path
                       && blogs.Published.Year == publishedDate.Year
                       && blogs.Published.Month == publishedDate.Month
                       && blogs.Published.Day == publishedDate.Day
                 select blogs).FirstOrDefault();

As Entity Framework did know how to pull out the Year, Month and Day properties of a DateTime object.

Overall neither of these were particularly big issues, but they caused some of the delays in getting the latest version of this site live - especially as most of the work on it is done late at night Wink

Filed under: Entity Framework, LINQ

I'd just like to thank...

Posted 26 November 2009, 19:32 | by | | Perma-link

As you may have noticed, I've had a bit of a change on the site - I rolled out the new look and feel back in September, before I'd put in place all the authoring controls, but as you can tell, I've been able to upload new photos recently, and I now have the blog authoring interface back in place as well.

Thanks go out to:

Now that this is all up and running again (other than a few tweaks here and there), hopefully we'll be publishing more content - starting with some posts on how I've found working with ASP.NET MVC, why I moved from LINQ to SQL to Entity Framework, and why that fixed the problems I was having, but introduced new ones that were harder to fix (I need to write that soon, before EF4 is released in March and makes this obsolete).

It's good to be back! Grin

Filed under: Site Updates

Forays in Photography

Posted 04 August 2009, 22:02 | by | | Perma-link

Inspired this morning by Scott Hanselman's tweet:

Some AMAZING High Dynamic Range photos. These are REAL photos.  http://bit.ly/kParz

I was inspired to do something. Limited by flat batteries, and missing the 5 minutes of exciting sunset this evening, I ended up with this image of the picture we bought on holiday last month, that is now hanging in the study. It's a mass produced photo on canvas, but quite nice:

Trees Triptych HDR Image
(Click for large version etc.).

I thought I'd also quickly run through the steps I went through on this. I started with three seperate photos taken from my camera, each taken manually, at the same focus, aperture and shutter speed, but with three different Exposure Compensations: -2EV, 0EV and +2EV - I went straight for the extremes:

Trees Triptych -2EVTrees Triptych 0EVTrees Triptych +2EV
The three exposures: Left to Right: -2EV, 0EV, and +2EV (click for large versions etc.).

I then dropped all three images into one layer in GIMP, in increasing order of exposure. this obviously resulted in the same image as the +2EV one above, however, once I started playing around with the layer modes, interesting things started to happen:

Trees Triptych -2EV base layer, 0EV Soft Light
The -2EV base layer, with the 0EV exposure with a layer mode of "Soft Light".

I then set the +2EV layer at the top with a layer mode of "Hard Light", and ended up with the image that started this post, which strangely seems to have more light coming from it that the original picture Grin

Filed under: Photography

Adding shipping methods to a Commerce Server Basket

Posted 11 May 2009, 23:26 | by | | Perma-link

This week, I have mostly been using Commerce Server. Well, to be honest it’s more like this month, but there we go. Seeing as I've only really ever managed other developers using Commerce Server, and we stuck pretty much to the "Let's try and make our business requirements line up with the starter site", this has been a fairly steep learning curve - as we're currently building a system with no inventory, nothing to deliver, and we're using a form building solution to create a heavily designed site - it's going to look great, but it might be painful getting there.

As you may have noticed from twitter, there are some things about this experience that I really don't appreciate in this day and age - most notably the whole magic string setup - although I guess that's partly due to the "extensible" nature of the system. But then there's the mixing of types - most things a user creates, such as catalogues, products, variants, discounts, etc have a string identifier, or possibly an integer if you're lucky, but then we got on to shipping methods - there aren't any, it's an online subscription, we have no stock (but for the last week all our products have been "out of stock"), so we have nothing to deliver, but I'm still getting pipeline errors because there's no shipping method associated with the basket.

So to the meat of this post: How do I associate a shipping method with a basket? I don't. I associate a shipping method with a Line Item - each and every one in the basket - and no way to say "apply this setting to all line items" - how often do you think to yourself on Amazon, "Oh, I'd like that CD to arrive tomorrow, but I don't mind if that one doesn't turn up for 5 days on their Super Saver Delivery™ option"? I know I don't, I just order stuff and have it turn up when it does, which pretty much ends up like that, as I order books that aren't out yet.

All I can say is thank you Microsoft for Object Initializers - they mean that I can at least do this:

// Get the current line items from the Commerce Sever basket
LineItemCollection currentItems = orderform.LineItems;
// Loop over the line items from the webservice call
foreach (wsLineItem wsItem in basketDetails.LineItems) {
  // See if we can find a line item in the basket that
  // matches the one from the web service
  csLineItem csItem = findLineItem(currentItems,
                                   wsItem.Catalogue,
                                   wsItem.Id,
                                   wsItem.VariationId);
  if (csItem == null) {
    /* We didn't find one, so add a new line item to the basket.
     * Here's where the magic happens - create a new line item with all
     * the properties we can set in the constructor, then add the remainder
     * through object initializers. */
     currentItems.Add(
              new csLineItem(wsItem.Catalogue,
                             wsItem.Id,
                             wsItem.VariationId,
                             wsItem.Quantity)
                             {ShippingMethodId = basketDetails.ShippingMethod});
  } else {
    // We found a match
    if (wsItem.Quantity == 0) {
      // The web service had 0 in the quantity - remove the item
      currentItems.Remove(csItem);
    } else {
      // The web service might have an updated quantity - update.
      csItem.Quantity = wsItem.Quantity;
    }
  }
}

Filed under: ASP.NET, Commerce Server