Recently I’ve been toying around with Contentful. A CMS with a fresh new approach to content management. The CMSs I’ve been working with in the past have been of the “install this package to your solution and build your templates”-variety. For example EPiServer, Joomla, Drupal, SiteCore etc. Contentful instead introduces the idea of managing your content separately in the cloud and accessing it through simple yet powerful REST apis.

Historically if a client would want to build a new website the dialogue might go something like this: “We’ll start by defining the look and feel for a few weeks, then we’ll start building the actual website, then we’ll deploy it to staging and there you can start creating your content which we’ll then copy over to production once ready”.

The problem with this approach is that the producing of content will have to wait as it is dependent on the presentation. This is of course far from ideal and contentful presents an interesting solution to this by moving the production of content into their cloud instead of into a management system tied to the actual website presenting it.

But what is the point, you might ask, of producing content with nowhere to present it yet? There might of course be several good reasons for this but a few that immediately cross my mind are;

  • You might want to postpone the selection of technical platform, but not fall behind in the production of content.
  • You might want to create content for several channels (mobile app, web site etc.), but none of them might be production ready yet.
  • You might want to get started creating content quickly. (Who wouldn’t?)

As just about everyone that has been involved in a CMS-project can witness; The production of content almost always comes too little, too late and presents the application with problems that historically have been very hard to catch during development and testing. By putting the content in the cloud we could use the exact same content in all environments, mitigating the problems of poor test data and making sure our design holds up in a production environment from day one.

While that sounds all fine and dandy, how does it really work?

Imagine we were hired to build a simple web application that needs to be powered by a CMS; it needs a StartPage and ArticlePages, logged in users should be able to like and comment certain pages. We should also be able to categorize pages by tags. All fairly common requirements for any CMS-project today. Let’s compare our process in building such an app in EPiServer (a traditional CMS) and Contentful.

For both systems we’d first have to identify our content types which in our simplified example is rather easy: StartPage, ArticlePage, Like, Comment and Tag are all good candidates. Now here’s where our process would start to diverge. In the EPiServer case we’d start writing code to hardwire our ContentTypes to database models. Something like this:


[ContentType]
public class StartPageContentType : PageData
 {
	public string Heading { get; set; }
 }

In Contentful no code would have yet to be written. We’d simply log into the user interface and start creating our ContentTypes, like so:

startpage

To be fair it is also possible to create content types through the web interface in EPiServer, but to do that we’d have to have the site up and running already… also, nobody does that because it makes it harder to create strongly typed models for your views.

We’d also have to create a couple of properties for our content types. In the EPi case this would correlate to actual C# properties and the EPiServer edit interface would translate this to editable properties. In Contentful the administrators of the content types would have to create the properties themselves and decide how they would be presented for editing. This is done in a few steps where we first decide which type of property we want:

startpage-proptypes

In our case we might want a title field to indicate the title of the startpage, a good choice for that would be a text property.

startpage-textprop

We would then configure the look and feel of the field and add things like validation.

startpage-validations

There are a bunch of other settings as well to really configure how this property should behave while creating our content.

In the EPi case we might decide to store comments and likes in separate database (probably not the EPiServer DDS though…) or perhaps as some sort of contenttype, like a comment block.

In Contentful we’d create a few more ContentTypes and link them together using a Reference property:

ref-property

Conceptually we’re doing the same thing as in EPiServer. Every startpage/articlepage can have many comments and likes.

Once we have all this set up correctly we can start consuming our content. In the EPi-case we’d setup controllers and views to present the content using our @Html.PropertyFor helper method, in Contentful we call the contentful API and get our content returned as JSON.

There are two separate APIs that we can call:

  • Content Delivery API
  • Content Management API

As you can probably guess we call the first one (Content Delivery) when we want to present content, but not modify it in any way. The Content Management API is called when we need to add/delete/update parts of our content.

Calling the Contenful API is crazy simple, just make a get request specifying what content you want and supply a correct access token and you’re good to go.

For example to get all created articlepages for our site we might call the api something like this:

https://cdn.contentful.com/spaces/space-id-here/entries?access_token=this-is-the-accesstoken&content_type=articlePage

This would return a json object containing all of our articlepages.


{
  "sys": {
    "type": "Array"
  },
  "total": 1,
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "sys": {
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "space-id-here"
          }
        },
        "id": "entry-id-here",
        "type": "Entry",
        "createdAt": "2016-04-13T17:37:35.831Z",
        "updatedAt": "2016-04-13T17:37:35.831Z",
        "revision": 1,
        "contentType": {
          "sys": {
            "type": "Link",
            "linkType": "ContentType",
            "id": "articlePage"
          }
        },
        "locale": "sv-SE"
      },
      "fields": {
        "title": "About us",
        "body": "Hello! This is the about us page."
      }
    }
  ]
}

We would then consume this JSON as we see fit and present the actual content to our visitor.

There are official SDKs available for many major languages, Ruby, Node.js, pure javascript, Swift, Android etc. There’s yet no official .NET SDK, but there’s an unofficial third part SDK that you can find here.

The pricing model is also highly attractive as compared to many of the commercial competitors. Up to 1000 content items, 3 users and 100k api-request/month is absolutely free. More than that costs from $99 to $199 a month depending on your needs. There’s also an enterprise model for companies with even greater demands.

As the api is rate limited it becomes very important to manage the amount of api-calls you make. Ideally you might want to cache the content returned from the API until they’re updated.

Heads up! As I wrote this blog post the good people of Contentful reached out to me and pointed out that they have multiple layers of internal caching. Both at the CDN level and below. They do not normally recommend that you cache at your application level as it is simply not necessary and adds unnecessary complexity. Also requests that hit the cache do not count towards your rate limit, which is fantastic! However, to make a point about the excellence of web hooks I’ll leave the short example below unaltered. But be advised that for an absolute majority of applications built on top of Contentful you would not have to implement any caching at all!

The problem with that would be that you need to be notified somehow when content is updated or created. Thankfully, being a modern and flexible platform, Contentful has embraced the concept of web hooks which make it dead simple to subscribe to events such as publishing, deleting and updating of content. We can set up a webhook for lots of different events and as the image below shows:

webhooks

This in conjunction with some clever caching would mean that you can keep the actual api-requests to a minimum while still responding instantly to content updates.

Is everything greener on the other side?

 

All in all I find the idea of separating content from presentation highly appealing and I hope that more companies start to look at this approach to content management. Not only is it beneficial for the content editors, being able to work without the interference of new code being deployed, without waiting for new properties to show up or bugs to be fixed, it is also highly beneficial for us developers; Being able to focus solely on the website/application consuming the content and not waste any time struggling with outdated CMS APIs and frustrating legacy wysiwyg editors.

That said though, change is always painful in one way or the other. I believe many EPiServer editors of today would feel a little lost without their trusty page tree representing the hierarchy of their pages. They might also miss the “on-page editing” capabilities introduced in EPiServer 7. Perhaps they’ll shed a tear for the dynamic properties, or maybe not…

I do believe, however, that they will love the lean, clean and intuitive edit interface in Contentful. The modern approach to handling digital assets (everything from markdown, to code, to video, images etc.) and the simplicity of creating content.

Change might be painful, but change is also inevitable. As the slow, ponderous behemoth CMSs of the past struggle to keep up with an ever changing and evolving web where front end frameworks have the life span of a dragonfly and major corporations change the rules for everybody, they might just see themselves get outpaced by the small and the nimble. And nimblest of them all is Contentful, CMS of the future…

I recently wrote an application where users had a need for some very specific searches. We decided to implement these searches as a query to the database. As we were using Entity Framework we first wrote our search implementation something like this:


    repository.Stuff.Where(c => c.SomeStuff.ToLower().Contains(query)) || c.SomeOtherStuff != null && c.SomeOtherStuff.Things.ToLower().Contains(query))

We had about 20ish different properties that we needed to null check and make a case insensitive search for. A couple of these properties belonged to entities in different tables than our imaginary Stuff table above and had "one to one" or "many to many" relationships.

The generated sql looked like something out of Edgar Allan Poes worst nightmares:

 
SELECT
    [UnionAll1].[Id] AS [C1],
    [UnionAll1].[Id1] AS [C2],
    [UnionAll1].[Id2] AS [C3],
    [UnionAll1].[Stuff] AS [C4],
    [UnionAll1].[Stuff2] AS [C5],
    [UnionAll1].[Stuff3] AS [C6],
    [UnionAll1].[Some_Id] AS [C7],
    [UnionAll1].[SomeOtherStuff] AS [C8],
    [UnionAll1].[Stuff666] AS [C9],
    [UnionAll1].[MoreStuff] AS [C10],
    [UnionAll1].[Things] AS [C11],
    [UnionAll1].[OtherThing] AS [C12],
    [UnionAll1].[Something] AS [C13],
    [UnionAll1].[PhoneNumberOrSomething] AS [C14],
    [UnionAll1].[AnotherThing] AS [C15],
    [UnionAll1].[MoreStuff] AS [C16],
    [UnionAll1].[AndMore] AS [C17],
    [UnionAll1].[MoreThings] AS [C18],
    [UnionAll1].[AndMoreMore] AS [C19],
    [UnionAll1].[Stuff4] AS [C20],
    [UnionAll1].[AndEvenMoreStuff] AS [C21],
    [UnionAll1].[CoolStuff] AS [C22],
    [UnionAll1].[SomeDate] AS [C23],
    [UnionAll1].[Stuff5] AS [C24],
    [UnionAll1].[Stuff6] AS [C25],
    [UnionAll1].[Stuff7] AS [C26],
    [UnionAll1].[AndSomeUserName] AS [C27],
    [UnionAll1].[BoolStuff] AS [C28],
    [UnionAll1].[BitStuff] AS [C29],
    [UnionAll1].[MoreThings] AS [C30],
    [UnionAll1].[Id3] AS [C31],
    [UnionAll1].[EvenMoreStuff] AS [C32],
    [UnionAll1].[AndMoreStuff] AS [C33],
    [UnionAll1].[Stuff8] AS [C34],
    [UnionAll1].[Stuff9] AS [C35],
    [UnionAll1].[IActuallyCantMakeUpMoreColumnNames] AS [C36],
    [UnionAll1].[Please] AS [C37],
    [UnionAll1].[No] AS [C38],
    [UnionAll1].[Moooore] AS [C39],
    [UnionAll1].[C1] AS [C40],
    [UnionAll1].[Id4] AS [C41],
    [UnionAll1].[ThisIsInsane] AS [C42],
    [UnionAll1].[StuffAgainAndAgain] AS [C43],
    [UnionAll1].[ICantTakeIt] AS [C44],
    [UnionAll1].[MakeItStop] AS [C45],
    [UnionAll1].[Almost] AS [C46],
    [UnionAll1].[JustAFewMore] AS [C47],
    [UnionAll1].[ComeOn] AS [C48],
    [UnionAll1].[AlmostThere] AS [C49],
    [UnionAll1].[Finally] AS [C50],
    [UnionAll1].[C2] AS [C51],
    [UnionAll1].[C3] AS [C52],
    [UnionAll1].[C4] AS [C53],
    [UnionAll1].[C5] AS [C54],
    [UnionAll1].[C6] AS [C55],
    [UnionAll1].[C7] AS [C56]
    FROM  (SELECT
        CASE WHEN ([Join2].[Some_Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1],
        [Extent2].[Id] AS [Id],
        [Extent1].[Id] AS [Id1],
        [Extent1].[Id] AS [Id2],
        [Extent1].[Stuff] AS [Stuff],
        [Extent1].[Stuff2] AS [Stuff2],
        [Extent1].[Stuff3] AS [Stuff3],
        [Extent1].[Person_Id] AS [Person_Id],
        [Extent1].[SomeOtherStuff] AS [SomeOtherStuff],
        [Extent1].[Stuff666] AS [Stuff666],
        [Extent1].[MoreStuff] AS [MoreStuff],
        [Extent1].[AndMore] AS [AndMore],
        [Extent1].[MoreThings] AS [MoreThings],
        [Extent1].[AndMoreMore] AS [AndMoreMore],
        [Extent1].[PhoneNumberOrSomething] AS [PhoneNumberOrSomething],
        [Extent1].[AnotherThing] AS [AnotherThing],
        [Extent1].[Things] AS [Things],
        [Extent1].[OtherThing] AS [OtherThing],
        [Extent1].[Stuff4] AS [Stuff4],
        [Extent1].[Stuff5] AS [Stuff5],
        [Extent1].[AndEvenMoreStuff] AS [AndEvenMoreStuff],
        [Extent1].[CoolStuff] AS [CoolStuff],
        [Extent1].[SomeDate] AS [SomeDate],
        [Extent1].[Stuff6] AS [Stuff6],
        [Extent1].[Stuff7] AS [Stuff7],
        [Extent1].[AndSomeUserName] AS [AndSomeUserName],
        [Extent1].[BitStuff] AS [BitStuff],
        [Extent1].[BoolStuff] AS [BoolStuff],
        [Extent1].[MoreThings] AS [MoreThings],
        [Extent1].[EvenMoreStuff] AS [EvenMoreStuff],
        [Extent1].[AndEvenMoreStuff] AS [AndEvenMoreStuff],
        [Extent2].[Id] AS [Id3],
        [Extent2].[MoreMoreMore] AS [MoreMoreMore],
        [Extent2].[Stuff8] AS [Stuff8],
        [Extent2].[Stuff9] AS [Stuff9],
        [Extent2].[IActuallyCantMakeUpMoreColumnNames] AS [IActuallyCantMakeUpMoreColumnNames],
        [Extent2].[Please] AS [Please],
        [Extent2].[No] AS [No],
        [Extent2].[Moooore] AS [Moooore],
        [Extent2].[ThisIsInsane] AS [ThisIsInsane],
        [Join2].[Id] AS [Id4],
        [Join2].[StuffAgainAndAgain] AS [StuffAgainAndAgain],
        [Join2].[ICantTakeIt] AS [ICantTakeIt],
        [Join2].[MakeItStop] AS [MakeItStop],
        [Join2].[Almost] AS [Almost],
        [Join2].[JustAFewMore] AS [JustAFewMore],
        [Join2].[ComeOn] AS [ComeOn],
        [Join2].[AlmostThere] AS [AlmostThere],
        [Join2].[Almoooost] AS [Almooost],
        [Join2].[Finally] AS [Finally],
        CAST(NULL AS int) AS [C2],
        CAST(NULL AS varchar(1)) AS [C3],
        CAST(NULL AS int) AS [C4],
        CAST(NULL AS varchar(1)) AS [C5],
        CAST(NULL AS datetime2) AS [C6],
        CAST(NULL AS int) AS [C7]
        FROM   [dbo].[StuffTable] AS [Extent1]
        INNER JOIN [dbo].[TableOfOtherStuff] AS [Extent2] ON [Extent1].[Some_Id] = [Extent2].[Id]
        LEFT OUTER JOIN  (SELECT [Extent3].[Other_Id] AS [Other_Id], [Extent3].[Stuff_Id] AS [Stuff_Id], [Extent4].[Id] AS [Id], [Extent4].[Stuff] AS [Stuff], [Extent4].[Morestuff] AS [MoreStuff], [Extent4].[AndMore] AS [AndMore], [Extent4].[EvenMore] AS [EvenMore], [Extent4].[MoreMoreMore] AS [MoreMoreMore], [Extent4].[MoreMoreMore] AS [MoreMoreMore], [Extent4].[ItNeverEnds] AS [ItNeverEnds], [Extent4].[ComeOnPlease] AS [ComeOnPlease], [Extent4].[Argh] AS [Argh]
            FROM  [dbo].[SomeOtherTable] AS [Extent3]
            INNER JOIN [dbo].[AndAnotherTableOfStuff] AS [Extent4] ON [Extent3].[Some_Id] = [Extent4].[Id] ) AS [Join2] ON [Extent1].[Id] = [Join2].[Some_Id]
        WHERE (([Extent1].[Stuff] IS NOT NULL) AND (LOWER([Extent1].[Stuff]) LIKE N'%rh%')) OR (([Extent1].[Stuff2] IS NOT NULL) AND (LOWER([Extent1].[Stuff2]) LIKE N'%rh%')) OR (([Extent1].[MoreStuff] IS NOT NULL) AND (LOWER([Extent1].[MoreStuff]) LIKE N'%rh%')) OR (([Extent1].[EvenMoreStuff] IS NOT NULL) AND ([Extent1].[EvenMoreStuff] LIKE N'%rh%')) OR (([Extent2].[Please] IS NOT NULL) AND (LOWER([Extent2].[Please]) LIKE N'%rh%')) OR (([Extent2].[MakeItStop] IS NOT NULL) AND (LOWER([Extent2].[MakeItStop]) LIKE N'%rh%')) OR (([Extent2].[Finally] IS NOT NULL) AND (LOWER([Extent2].[Finally]) LIKE N'%rh%'))
    UNION ALL
        SELECT
        2 AS [C1],
        [Extent6].[Id] AS [Id],
        [Extent5].[Id] AS [Id1],
        [Extent5].[Id] AS [Id2],
        [Extent5].[Stuff] AS [Stuff],
        [Extent5].[MoreStuff] AS [MoreStuff],
        [Extent5].[Stuff2] AS [Stuff2],
        [Extent5].[Some_Id] AS [Some_Id],
        [Extent5].[Stuff3] AS [Stuff3],
        [Extent5].[EvenMoreStuff] AS [EvenMoreStuff],
        [Extent5].[SomeOtherStuff] AS [SomeOtherStuff],
        [Extent5].[Stuff666] AS [Stuff666],
        [Extent5].[AndMore] AS [AndMore],
        [Extent5].[MoreThings] AS [MoreThings],
        [Extent5].[Thingy] AS [Thingy],
        [Extent5].[OtherThing] AS [OtherThing],
        [Extent5].[AndSomeUserName] AS [AndSomeUserName],
        [Extent5].[PhoneNumberOrSomething] AS [PhoneNumberOrSomething],
        [Extent5].[ItNeverEnds] AS [ItNeverEnds],
        [Extent5].[ItGoesOnAndOn] AS [ItGoesOnAndOn],
        [Extent5].[AndOnAndOn] AS [AndOnAndOn],
        [Extent5].[Please] AS [Please],
        [Extent5].[AnotherColumn] AS [AnotherColumn],
        [Extent5].[IActuallyCantMakeUpMoreColumnNames] AS [IActuallyCantMakeUpMoreColumnNames],
        [Extent5].[Stuff4] AS [Stuff4],
        [Extent5].[Stuff5] AS [Stuff5],
        [Extent5].[BitStuff] AS [BitStuff],
        [Extent5].[BoolStuff] AS [BoolStuff],
        [Extent5].[CoolStuff] AS [CoolStuff],
        [Extent5].[SomeDate] AS [SomeDate],
        [Extent5].[StuffAgainAndAgain] AS [StuffAgainAndAgain],
        [Extent6].[Id] AS [Id3],
        [Extent6].[ICantTakeIt] AS [ICantTakeIt],
        [Extent6].[MakeItStop] AS [MakeItStop],
        [Extent6].[AlmostThere] AS [AlmostThere],
        [Extent6].[JustAFewMore] AS [JustAFewMore],
        [Extent6].[ComeOn] AS [ComeOn],
        [Extent6].[Almost] AS [Almost],
        [Extent6].[Almoooost] AS [Almoooost],
        [Extent6].[Finally] AS [Finally],
        CAST(NULL AS int) AS [C2],
        CAST(NULL AS varchar(1)) AS [C3],
        CAST(NULL AS varchar(1)) AS [C4],
        CAST(NULL AS varchar(1)) AS [C5],
        CAST(NULL AS varchar(1)) AS [C6],
        CAST(NULL AS varchar(1)) AS [C7],
        CAST(NULL AS varchar(1)) AS [C8],
        CAST(NULL AS varchar(1)) AS [C9],
        CAST(NULL AS bit) AS [C10],
        CAST(NULL AS bit) AS [C11],
        [Extent7].[Id] AS [Id4],
        [Extent7].[Url] AS [Url],
        [Extent7].[SomeThing] AS [SomeThing],
        [Extent7].[MoreStuff] AS [MoreStuff],
        [Extent7].[Crazy] AS [Crazy],
        [Extent7].[StuffId] AS [StuffId]
        FROM   [dbo].[Thingies] AS [Extent5]
        INNER JOIN [dbo].[SomeOtherTable] AS [Extent6] ON [Extent5].[Some_Id] = [Extent6].[Id]
        INNER JOIN [dbo].[AndAnotherTable] AS [Extent7] ON [Extent5].[Id] = [Extent7].[StuffId]
        WHERE (([Extent5].[Stuff] IS NOT NULL) AND (LOWER([Extent5].[Stuff]) LIKE N'%rh%')) OR (([Extent5].[Stuff2] IS NOT NULL) AND (LOWER([Extent5].[Stuff2]) LIKE N'%rh%')) OR (([Extent5].[SomeOtherStuff] IS NOT NULL) AND (LOWER([Extent5].[SomeOtherStuff]) LIKE N'%rh%')) OR (([Extent5].[EvenMoreStuff] IS NOT NULL) AND ([Extent5].[EvenMoreStuff] LIKE N'%rh%')) OR (([Extent6].[Please] IS NOT NULL) AND (LOWER([Extent6].[Please]) LIKE N'%rh%')) OR (([Extent6].[NoMore] IS NOT NULL) AND (LOWER([Extent6].[NoMore]) LIKE N'%rh%')) OR (([Extent6].[Finally] IS NOT NULL) AND (LOWER([Extent6].[Finally]) LIKE N'%rh%'))) AS [UnionAll1]
    ORDER BY [UnionAll1].[Id] ASC, [UnionAll1].[Id2] ASC, [UnionAll1].[Id3] ASC, [UnionAll1].[C1] ASC

my-eyes

This literally hurts to look at... and needless to say resulted in abysmal performance.

The query in itself took about 10-15 seconds to execute over a dataset of about 15 000 records... It was time to look at the alternatives.

We immediately gave up on Entity Framework for these queries. Now, don't get me wrong, I really like Entity Framework, the problem here isn't the framework in itself it's the ungrateful queries we give it to process. As Entity Framework is a "one shoe fits all"-solution that is a great tool in a wide spectrum of use cases it simply does not perform well with specialized queries such as these. You could of course execute plain sql queries through the DbContext, but this still comes with considerable overhead and the mapping to objects is not as streamlined as one could wish.

Enter dapper

quite-dapper

Dapper is a "simple object mapper for .Net" that simply extends the IDbConnection interface and provides helper methods to execute a query or command and map the results to simple POCO .Net objects. It is extremely performant and light weight.

Our implementation with dapper took our initial query and made it look something like this:


SELECT TOP 10
StuffTable.Id,
Stuff collate sql_latin1_general_cp1_ci_as AS Stuff,
StuffTable.StuffNumber collate sql_latin1_general_cp1_ci_as AS StuffNumber,
MoreStuff collate sql_latin1_general_cp1_ci_as AS MoreStuff,
Stuff666 collate sql_latin1_general_cp1_ci_as AS Stuff666,
ThingsTable.ThingsNumber collate sql_latin1_general_cp1_ci_as AS ThingsNumber,
ThingsTable.Thingy collate sql_latin1_general_cp1_ci_as AS Thingy,
ThingsTable.OtherThing collate sql_latin1_general_cp1_ci_as AS OtherThing,
OtherTable.OtherStuff collate sql_latin1_general_cp1_ci_as AS OtherStuff,
OtherTable.EvenMoreStuff collate sql_latin1_general_cp1_ci_as  AS EvenMoreStuff,
LEFT(Thingy, 1) + ' ' + LEFT(OtherThing, 1) AS WeirdStuff
FROM dbo.StuffTable
LEFT JOIN dbo.ThingsTable ON ThingsTable.Id = Cases.Thing_Id
LEFT JOIN dbo.StuffTableToOtherTable ON StuffTableToOtherTable.Stuff_Id = StuffTable.Id
LEFT JOIN dbo.OtherTable ON OtherTable.Id = StuffTableToOtherTable.Other_Id
 
WHERE
LEFT(Thingy, 1) + ' ' + LEFT(OtherThing, 1) = 'r l' OR
Stuff LIKE '%r l%' OR
StuffNumber LIKE '%r l%' OR
MoreStuff LIKE 'r l%' OR
Stuff666 LIKE 'r l%' OR
ThingsNumber LIKE '%r l%' OR
Thingy LIKE 'r l%' OR
OtherThing LIKE 'r l%' OR
Thingy + ' ' + OtherThing LIKE 'r l%' OR
OtherStuff LIKE 'r l%' OR
EvenMoreStuff LIKE '%r l%'

Yeah, it still isn't very pretty, but lets face it; A complicated SQL query will never be more than half readable...

To execute the query with dapper we simply do something like this:


 var query = //our crazy query from above, omitted for brevity
 var dbConnection = //our database connection of type IDbConnection
 
 var res = dbConnection.Query<AwesomeResult>(query);


We execute the result on our database connection and dapper maps it automatically to our AwesomeResult class.

With this approach our once monstrously slow query took about 14ms to execute.

I’ve been working quite alot on database-intensive applications lately and have been setting up a simple repository pattern with structuremap that I thought might be of interest.

First things first, I love structuremap, it’s an excellent IoC framework and it makes life so much easier when used to its full potential. Not just for dependency injection but for making applications truly loosely coupled. One oftenly overlooked feature is Structuremaps ability to decorate an inner class with a wrapper. Have a look at this for example:

For<IMovieRepository>().Use<MovieRepository>();
For<IMovieRepository>().DecorateAllWith<CachingMovieRepository>();

What we're doing here is simply injecting a concrete implementation for IMovieRepository called MovieRepository and then decorating or wrapping it with another concrete implementation called CachingMovieRepository. We could continue this chain with another wrapper, and another and another. Perhaps something like this:

For<IMovieRepository>().Use<MovieRepository>();
For<IMovieRepository>().DecorateAllWith<CachingMovieRepository>();
For<IMovieRepository>().DecorateAllWith<AuditingMovieRepository>();
For<IMovieRepository>().DecorateAllWith<LoggingMovieRepository>();

The outermost wrapper would now be a LoggingMovieRepository, which in turn would call an AuditingMovieRepository, which in turn would call a CachingMovieRepository that finally would call the MovieRepository and return some movies (hopefully).

This might sound weird and not make much sense if you’re not into IoC or the decorator pattern, but let me continue the example by showing the IMovieRepository interface (simplified of course) and just some possible implementations of the different implementors.

public interface IMovieRepository {
    Movie GetById(int id);
}

The interface, simplified to one method.

public class MovieRepository : IMovieRepository {
    Movie GetById(int id) {
        //Some db-call to fetch a movie and return it
        //For example:
        return dbContext.Movies.FindById(id);
    }
}

The only concrete implementation that actually does the heavy lifting of getting a movie from the database. Nothing really to see here.

public class CachingMovieRepository : IMovieRepository {

    private readonly IMovieRepository _repo;
    private readonly ICacheManager _cache;

    public CachingMovieRepository(IMovieRepository repo, ICacheManager cacheManager) {
        _repo = repo;
        _cache = cacheManager;
    }

    Movie GetById(int id) {
        //We try to get the movie from the cache
        var movie = _cache.TryGetMovie(id);
        
        if(movie == null)
        {
            return _repo.GetById(id);
        }
        return movie;
    }
}

Now it's getting interesting, the caching repo implements the interface and takes a parameter for another IMovieRepository to call in case it does not find the requested movie in the cache. It also needs an ICacheManager to do the actual cache look up.

public class AuditingMovieRepository : IMovieRepository {

    private readonly IMovieRepository _repo;
    private readonly IAuditManager _audit;

    public AuditingMovieRepository (IMovieRepository repo, IAuditManager audit){
        _repo = repo;
        _audit = audit;
    }

    Movie GetById(int id) {
        //We audit the call
        _audit.AuditGetMovie(int id);
        
        return _repo.GetById(id);
    }
}

And we can see the pattern forming, every IMovieRepository takes another IMovieRepository to call after it has completed its operations. In this case just auditing the call to the database and perhaps save who accessed which table for which entity.

public class LoggingMovieRepository : IMovieRepository {

    private readonly IMovieRepository _repo;
    private readonly ILogManager_log;

    public LoggingMovieRepository (IMovieRepository repo, ILogManager log){
        _repo = repo;
        _log = log;
    }

    Movie GetById(int id) {
        //We log the call
        _log.LogInfo(String.Format("Getting movie {0} from database", id));

        return _repo.GetById(id);
    }
}

And we now have four completely different implementations of IMovieRepository each with it's own unique responsiblity. And the best part? They need to know absolutely nothing of each other. We could even switch the order of operations around by simply changing our structuremap configuration, like so:

For<IMovieRepository>().Use<MovieRepository>();
For<IMovieRepository>().DecorateAllWith<CachingMovieRepository>();
For<IMovieRepository>().DecorateAllWith<LoggingMovieRepository>();
For<IMovieRepository>().DecorateAllWith<AuditingMovieRepository>();

And suddenly the auditing happens before the logging.

To be able to fully utilize this pattern I have composed a simple asynchronous and generic repository interface that looks like this:

public interface IRepository<TEntity>
    {
        Task<TEntity> GetByIdAsync(int id);
 
        IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
 
        IQueryable<TEntity> GetAll();
 
        Task UpdateAsync(TEntity entity);
 
        Task InsertAsync(TEntity entity);
 
        Task DeleteAsync(TEntity entity);
    }

This combined with an abstract base class forms a solid foundation for dataaccess that can be easily extended with the decorator pattern. Here's the base class:

public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected DbSet<TEntity> DbSet;
 
        protected readonly AppDbContext _dbContext;
 
        public BaseRepository(AppDbContext dbContext)
        {
            _dbContext = dbContext;
            DbSet = _dbContext.Set<TEntity>();
        }
 
        public virtual IQueryable<TEntity> GetAll()
        {
            return DbSet;
        }
 
        public virtual async Task<TEntity> GetByIdAsync(int id)
        {
            return await DbSet.FindAsync(id);
        }
 
        public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
        {
            return DbSet.Where(predicate);
        }
 
        public virtual async Task UpdateAsync(TEntity entity)
        {
            _dbContext.SetModified(entity);
            await _dbContext.SaveChangesAsync();
        }
 
        public virtual async Task InsertAsync(TEntity entity)
        {
            DbSet.Add(entity);
            await _dbContext.SaveChangesAsync();
        }
 
        public virtual async Task DeleteAsync(TEntity entity)
        {
            DbSet.Attach(entity);
            DbSet.Remove(entity);
            await _dbContext.SaveChangesAsync();
        }
    }

A very rudimentary implementation of the interface, it works for most simple data access scenarios. One thing to note is that I have extended the regular DbContext with a virtual method .SetModified(entity);. This is merely for unit testing purposes as it is otherwise hard to unit test the non virtual Entry() method.

Here's the SetModified method for the sake of completeness:

//This is here only for unit testing purposes
public virtual void SetModified(object entity)
    {
        Entry(entity).State = EntityState.Modified;
    }

There we go, all the plumbing done and over with... Lets say we now actually wanted to create a movie repository and start storing some movies.

Lets start with creating our movie class, a simple POCO object (we'll use Entity Framework code first to create the database).

public class Movie
    {
        public string Name { get; set; }
        public int Length { get; set; }
        public string Description { get; set; }
    }

Alot more should of course go into this class, like Directors, Genres etc. but lets keep it simple for now.

We need to add this as a DbSet to our DbContext class, something like this.

public class AppDbContext : DbContext {
    public DbSet<Movie> Movies { get; set; }
}

And now we just need an implementation of BaseRepository and we're ready to access some data.

public class MovieRepository : BaseRepository<Movie> {
    public MovieRepository(AppDbContext context) : base(context) {
    }
}

Now if we had an MVC controller where we needed to access a Movie and use it as a model we would do something along the lines of this:

public class MoviesController : Controller {

    private readonly IRepository<Movie> _repo;
    
    public MoviesController(IRepository<Movie> repo) {
        _repo = repo;
    }

    public async Task<ActionResult> Index(int id) {
        var model = await _repo.GetByIdAsync(id);

        return View(model);
    }
}

We use constructor injection here to inject an IRepository<Movie> into our controller, this would be populated by Structuremap and could be wrapped by any of our implementations of the IRepository interface. And that's the beauty of it! The controller doesn't even need to know which implementation it will be calling or what it will be doing. All it needs to know is that it will be passed an IRepository dependency and should expect to get a Movie entity from it.

I’ve been using several different ways of highlighting code on this blog over the years. Since I re-launched it about a year ago I use only Windows Live Writer as my tool for authoring the blog posts and have tried a number of plug-ins with varying success. The formatting of the code is usually quite allright, but the mark-up it spits out is just horrific. It looks like in the old days of pasting from word documents into dreamweaver and seeing something like this:

<p class=”MsoNormal”><p class=”MsoTac1><font size=”5” face=”Cambria”><span style=”font-family:Cambria;font-size:18.0pt;font-weight:bold”>The quick brown fox jumped all the hell around and spewed terrible html mark up to the left and right</span></font></p></p>

Absolutely terrifying. Anyway, I decided it was time for a spring cleaning and looked around at different options. I had a particular set of goals in mind:

  • Readability – it must be easy for consumers of the blog to read the code.
  • Extensibility – I must be able to extend functionality of the highlighting as I see fit.
  • Simplicity – It must be simple for me to paste and edit code with it using WLW.
  • Speed – It must load fast and be light as to not impact the load time of the blog negatively.
  • Languages – It must support different languages such as JavaScript, C#, markup, XML etc.

I stumbled around and tried a few until I found my perfect match: Prismjs! I selected the dark (almost Atom-like) theme Okaida by Ocodia just to get some contrast to the themes I used before.

Prismjs core is less than 2k, blazingly fast and uses semantic non-cluttering html 5 mark up. It’s also fully open source and supports most about every programming language you can think of.

Here’s what it looks like for some javascript:

var inputDelay = (function () {
    var timer = 0;
    return function (callback, ms) {
        clearTimeout(timer);
        timer = setTimeout(callback, ms);
    };
})();

Now that's nice, but what's even nicer is that I just copied this code-snippet and pasted it in Windows Live Writer and it automatically wrapped it in <pre> and <code> tags for me which is all prismjs needs to do its magic! In this case, as it’s javascript, I had to manually add the class=”language-javascript” attribute, but that’s a minor price to pay. I have defaulted my language to c# so if I were to paste som cool .net stuff in here like this:

public enum Suits
{
    Spades,
    Hearts,
    Clubs,
    Diamonds,
    NumSuits
}

public void PrintAllSuits()
{
    foreach (string name in Enum.GetNames(typeof(Suits)))
    {
        System.Console.WriteLine(name);
    }
}

I wouldn’t even have to add the class. It just automatically works. Now that’s simplicity!

To the cloud!

While i was in the mood for changing things up I also decided to move the hosting of my website to Azure. Not because I was dissatisfied with my current web hosting at Binero, but because I got inspired by Troy Hunt and his website http://worldsgreatestazuredemo.com/. The process of setting up a new site in Azure is dead simple. It takes about 5 minutes to have a brand new site up and running. In my case I set it up with deploy from GitHub, which means I actually write and publish my blog posts locally and then commit them into git. Azure automatically picks it up and deploys it. This brought one problem though… comments.

I previously handled comments as part of the blog post. Every comment would be stored in the XML representing a post and that was all fine and dandy. However, as I am now pushing my posts from source control that would mean that I would overwrite any comments with every commit. How do we get around that?

The cloud to the rescue! There are several different cloud based commenting solutions but I decided to go with disqus, a clean and simple api, support for facebook, twitter, google logins and an unobtrusive interface.

So what do you think of the new theme for code highlighting? Let me know in the (new) comments.

The new Inversion of Control pattern introduced with EPiServer 7 is, in my opinion, one of the best new features of EPiServer CMS. Anywhere in your application you can simply call the ServiceLocator and GetInstance <ISomeInterface>() and it will return the concrete implementation of your choosing of that interface.

This is of course nothing new, StructureMap has been around for years and there are dozens of other excellent frameworks for IoC.

However, in the EPiServer world this is still kind of new and I’ve seen several epi-projects where the concept of IoC is still largely misunderstood. But this is not a post about IoC as such, but if you’re interested here’s an introduction to StructureMap, it’s a pretty old post but still interesting.

I was working in a project recently where we created a couple of concrete implementations for cache handling. A CacheManager and a NullCacheManager, the CacheManager utilized the HttpRuntime.Cache in the background, the NullCacheManager simply cached nothing as one would expect. They both implement the ICacheManager interface, shown highly simplified below.

public interface ICacheManager {

 GetCachedItem<T>(string key, Func<T> uncachedMethod);

 SetCachedItem<T>(string key, T item);

 RemoveCachedItem(string key); 

}

This was all good and we could now easily decouple our design using code looking something like this.

public void SomeMethod() {

 var cacheManager = ServiceLocator.Current.GetInstance<ICacheManager>();

 var cachedItem = cacheManager.GetCachedItem<SomeObject>("key", SomeMethodThatFetchesSomObjectUnCached);

}

This is great and gives us a very loosely coupled design. We could easily create a new concrete type of ICacheManager such as SqlCacheManager or FileSystemCacheManager and switch between the implementations using a ConfigureableModule, something like this:

public class ConfigureableModule : IConfigurableModule
	{
		public void ConfigureContainer(ServiceConfigurationContext context)
		{
		    var container = context.Container;

		    container.Configure(c => c.For<ICacheManager>().Use<CacheManager>());
		}
	}

We could also have different concrete implementations for different environments by using profiles, like this:

public class ConfigureableModule : IConfigurableModule
 {
     public void ConfigureContainer(ServiceConfigurationContext context)
	{
		var container = context.Container;

		container.Configure(c => { 
			c.Profile("debug", ctx => { ctx.For<ICacheManager>().Use<NullCacheManager>(); 

			c.Profile("release", ctx => { ctx.For<ICacheManager>().Use<CacheManager>(); 
				}); 
			});  
		});
	}
 }

But wouldn’t it be pretty cool if we could switch the implementation at runtime? Turns out it’s not too difficult to achieve… Lets create an admin plugin where an administrator can choose which implementation of ICacheManager should currently be used by the site.

We start out by creating a simple plugin:

[EPiServer.PlugIn.GuiPlugIn(Area = EPiServer.PlugIn.PlugInArea.AdminConfigMenu, Url = "/modules/samplesite/ChangeCacheManager/Index", DisplayName = "Cache management")]
[Authorize(Roles = "Administrators")]
public class ChangeCacheManagerController : Controller
 {
	public ActionResult Index() { return View(); }
 }

Remember that we need to add this nonsense to the episerver.shell part of our web.config as well for our module to be picked up:


<episerver.shell>
    <publicModules rootPath="~/modules/" autoDiscovery="Minimal">
      <add name="samplesite">
        <assemblies>
          <add assembly="WhateverYouNameYourAssembly" />
        </assemblies>
      </add>
   </publicModules>
</episerver.shell>

Also please note that I’ve added an authorization attribute to the controller to make sure noone but an administrator stumbles upon it.

Add an empty index.cshtml view for now and type something awesome in it. Compile and run and make sure your plugin appears in the admin config menu.

Allright, next lets create a model for our view.

public class CacheManagerViewModel {

	public string SelectedManager { get; set; }

	public List<SelectListItem> ConfiguredManagers { get; set; }

	public CacheManagerViewModel() {
		ConfiguredManagers = new List<SelectListItem>();
	}
}

Simple, all our plugin will need is a list of the available cachemanagers and a string representing the currently selected one. Ok, lets flesh out our view next.

@model Afa.web.AdminPlugins.Models.CacheManagerViewModel
<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="/EPiServer/Shell/7.11.1.0/ClientResources/epi/themes/legacy/ShellCore.css">
        <link rel="stylesheet" type="text/css" href="/EPiServer/Shell/7.11.1.0/ClientResources/epi/themes/legacy/ShellCoreLightTheme.css">
        <link href="../../../App_Themes/Default/Styles/ToolButton.css" type="text/css" rel="stylesheet">
        <title>Cache management</title>
    </head>
    <body>
        <div class="epi-contentContainer epi-padding">
            <h1>Select active cachemaanger</h1>
            <p>Select which CacheManager implementation to use for this site.</p> 

            @using (Html.BeginForm())
            {
                <div class="epi-padding">
                    <p>Currently active cachemanager: <strong>@Model.SelectedManager</strong></p>
                    <div class="epi-size25">                       
                        <div>

                            <label>Select cachemanager: </label>

                            @Html.DropDownListFor(m => m.SelectedManager, Model.ConfiguredManagers, new { @class = "episize240" })

                        </div>
                    </div>
                </div> 

                    <div class="epi-buttonContainer">

                    <span class="epi-cmsButton">

                        <input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Save" type="submit" value="Save" />

                    </span>

                </div>
            }
        </div>
    </body>
</html>

Now we have a model and a view, all that’s left is to add some code to our controller:


public ActionResult Index()
{
    return View(GetViewModel());
}

[HttpPost]
public ActionResult Index(CacheManagerViewModel model)
{
    var container = ServiceLocator.Current.GetInstance<IContainer>(); 

    var selectedManager = Type.GetType(model.SelectedManager); 

    container.Model.EjectAndRemoveTypes(t => t == selectedManager);

    var instance = (ICacheManager)container.GetInstance(selectedManager);

    container.Configure(x => x.For<ICacheManager>().Use(instance));

    return View(GetViewModel());
} 

private CacheManagerViewModel GetViewModel()
{
    var model = new CacheManagerViewModel();

    var currentActiveManager = ServiceLocator.Current.GetInstance<ICacheManager>();

    model.SelectedManager = currentActiveManager.GetType().Name;

    foreach (var manager in ServiceLocator.Current.GetAllInstances<ICacheManager>())
    {
        model.ConfiguredManagers.Add(new SelectListItem()
       {
          Text = manager.GetType().Name,

          Value = manager.GetType().AssemblyQualifiedName,

          Selected = currentActiveManager.GetType() == manager.GetType()

        });
     }
     return model;
}

There are a few interesting points in the code above. Lets first consider GetViewModel() method. We simply get the currently active concrete implementation and then loop through all instances of ICacheManager that is currently registered in our IoC container. This brings us to an important point, allimplementations of ICacheManager must have been registered in our container or they wont be returned by the GetAllInstances method. This could be done in simple fashion by using the AddAllTypesOf<ICacheManager> when we configure our container. Something like this:

public void ConfigureContainer(ServiceConfigurationContext context) {

	context.Container.Configure(c => c.Scan(s => s.AddAllTypesOf<ICacheManager>()));
}

Next lets have a look at the post method. This method looks kinda peculiar, what’s all this ejecting and removing stuff? It turns out that we can’t really just change which configured cachemanager to use with For.Use because that would add another instance of the same type and not replace the existing one, and that’s why we first need to eject the model of the selected type and then re-configure it.

And that should be it! We now have a working admin plugin that lets us change fundamental inner workings of our application at runtime. We could substitute ICacheManager for IContentRepository and radically change how we fetch our content, we could substitute it for IContentRenderer and add functionality such a detailed logging to the rendering of our content… There’s no end to the possibilities!

But, as we’ve learned from modern classics such as the bible and the amazing spiderman:

spider