November Happy Hour will be moved to Thursday December 5th.

Hjalmar Moa
Jan 27, 2010
  7067
(0 votes)

Some thoughts on using the Repository design pattern

There is plenty of talk about MVC vs. Web Forms going on. One thing that MVC pushes for is small controller classes and a rich domain model. A rich domain model is equally useful in Web Forms but somehow seldom implemented.

Using a tiered design, logic is to be placed in the business layer and the presentation should be in the user interface. A lot of times business logic is nested with presentation logic in a big non-reusable pile.

One way to move some logic into the business layer is to create a “Repository” class for some types of data.

As an example, a CalendarEventRepository could be created that get the events which are displayed in the calendar on a website.

The following example shows you how to fetch pages from a set location. The page types are specified with Page Type Builder so we can filter them by type in an easy way.

   1:  public class CalendarEventRepository : RepositoryBase<CalendarItemPageType>
   2:      {
   3:          /// <summary>
   4:          /// Get the calendar events from the specified year
   5:          /// </summary>
   6:          /// <param name="language">language branch</param>
   7:          /// <returns>all events</returns>
   8:          public static ICalendarEvent[] GetCalendarEvents(string language)
   9:          {
  10:              CalendarItemPageType[] items = GetPagesFrom(SettingsPageType.Instance.CalendarPage, language);
  11:              if (items == null)
  12:              {
  13:                  log4net.LogManager.GetLogger("CalendarEventRepository")
  14:                      .Debug("Settings.CalendarPageLink is not set");
  15:   
  16:                  return new ICalendarEvent[0];
  17:              }
  18:              if (items.Length == 0)
  19:              {
  20:                  log4net.LogManager.GetLogger("CalendarEventRepository")
  21:                      .Debug("No pages of type 'CalendarItemPageType' below page " + SettingsPageType.Instance.CalendarPage.ID);
  22:   
  23:                  return new ICalendarEvent[0];
  24:              }
  25:   
  26:              items = items
  27:                  .OrderBy(page => page.PageDate)
  28:                  .ToArray();
  29:   
  30:              return items;
  31:          }

The base class has a function that get the pages of choice

   1:      public abstract class RepositoryBase<T> where T: TypedPageData
   2:      {
   3:          protected static T[] GetPagesFrom(PageReference pageLink, string language)
   4:          {
   5:              if (PageReference.IsNullOrEmpty(pageLink)) return null;
   6:              PageDataCollection children = DataFactory.Instance.GetChildren(pageLink, new LanguageSelector(language));
   7:              EPiServer.Filters.FilterForVisitor.Filter(children);
   8:   
   9:              T[] items = children
  10:                  .Where(page => page is T)
  11:                  .Select(page => page as T)
  12:                  .ToArray();
  13:   
  14:              return items;
  15:          }

 

Our page type implements an interface so we can return a loosely coupled reference:

   1:      public class CalendarItemPageType : DatePageType, ICalendarEvent
 

The advantages

“Separation of concerns” has been a big topic lately. The page shouldn’t have to know how the calendar is implemented, it should trust the repository to send the data it needs. The repository should just serve the data and not be bothered who uses it.

The repository returns an interface for the same reason. The class using the repository doesn’t need to know that the repository is really just returning a page.

Having returned an interface gives us the freedom to change the implementation of the repository without changing anything else on the site. The events could equally well be classes hosted in the Dynamic Data Store, or returned from a RSS feed.

Is it worth the bother?

I have heard some times that it is overkill to create an entirely new class just to get some child pages.

This might seem a good enough reason to start with, but code tends to grow overtime. Soon the excuse is that it is too many places to change instead.

The second excuse is that it is too hard to understand code that uses interfaces. I don’t have a good comment on this….

What’s your opinion?

Jan 27, 2010

Comments

Sep 21, 2010 10:33 AM

Good one, Hjalmar!

I believe I have to get knee-deep with your solution in a project to see the benefits. I do, however, love separation of logic in your approach.

Very elegant code. :) Major kudos!

Hope everything is well up with you and the team in the H&H fortress!
/ Daniel Berg

Please login to comment.
Latest blogs
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog