Stefan Forsberg
Dec 21, 2010
  4471
(2 votes)

Create stores for the dynamic data store

I’ve started to study for the certification test and since there are quite a few areas in CMS 6 I haven’t used I started with one of those (hey, everything beats reading up on mirroring right?) namely the dynamic data store.

Also, if you’ve fallen asleep before reaching the end of the post I’ll take this opportunity to wish you a merry Christmas!

When it comes to DDS one thing I quite soon found myself doing was checking if a store existed and create it if not. This seemed like a good opportunity to showcase both how to use StructureMap as well as some testing. Basically this is the same blog post I always write but with new fancy classes!

I’ve chosen to create a store from a type so the first thing to create is an interface that specifies which type we want to create a store for.

   1: public interface ISpecifyTypeForDynamicDataStore
   2: {
   3:     Type GetType();
   4: }

My dynamic data class implements it (as well as IDynamicData).

   1: public class TaskInfo : IDynamicData, ISpecifyTypeForDynamicDataStore
   2: {
   3:     public Identity Id { get; set; }
   4:     public string Name { get; set; }
   5:  
   6:     Type ISpecifyTypeForDynamicDataStore.GetType()
   7:     {
   8:         return this.GetType();
   9:     }
  10: }

And that’s all I need to do.

Under the hood

The basic flow for the code that actually performs the creating of stores is the following:

Find all classes that implements ISpecifyTypeForDynamicDataStore

Get the type from those classes and create a list

Send the list to some class that checks if the store already exist for that type. If it does not, create it.

Finding all types that implements ISpecifyTypeForDynamicDataStore

An operations like this is quite simple using StructureMap. We simply specify that we want to register all implementations of the interface (line 10) in question and StructureMap will add all to it’s container.

   1: public static void BootstrapStructureMap(IContainer container)
   2: {
   3:     container
   4:         .Configure(x =>
   5:        {
   6:            x.Scan(a =>
   7:           {
   8:               a.AssembliesFromApplicationBaseDirectory();
   9:               a.LookForRegistries();
  10:               a.AddAllTypesOf<ISpecifyTypeForDynamicDataStore>();
  11:           });
  12:        }
  13: );
  14: }

I’ve also created a registry so StructureMap knows which concrete implementation we want for the abstract class DynamicDataStoreFactory.

   1: public class DdsRegistry : Registry
   2: {
   3:     public DdsRegistry()
   4:     {
   5:         For<DynamicDataStoreFactory>()
   6:             .Use(DynamicDataStoreFactory.Instance);
   7:     }
   8: }

Creating the stores

The actual creating of stores is handled by a class that’s responsible for creating the store. This basically boils down to enumerating through a list of types and if the type does not have a connected store it should create one.

   1: public class CreateDynamicDataStores
   2:     {
   3:         private readonly DynamicDataStoreFactory _dynamicDataStoreFactory;
   4:         private readonly List<ISpecifyTypeForDynamicDataStore> _types;
   5:  
   6:         public CreateDynamicDataStores(DynamicDataStoreFactory dynamicDataStoreFactory, List<ISpecifyTypeForDynamicDataStore> types)
   7:         {
   8:             _dynamicDataStoreFactory = dynamicDataStoreFactory;
   9:             _types = types;
  10:         }
  11:  
  12:         public void CreateStoreIfItDoesNotExist()
  13:         {
  14:             foreach (var type in _types.Select(t => t.GetType()))
  15:             {
  16:                 if (!DoesStoreExist(type))
  17:                 {
  18:                     CreateStore(type);
  19:                 }
  20:             }
  21:         }
  22:  
  23:         private void CreateStore(Type type)
  24:         {
  25:             _dynamicDataStoreFactory.CreateStore(type);
  26:         }
  27:  
  28:         private bool DoesStoreExist(Type type)
  29:         {
  30:             return _dynamicDataStoreFactory.GetStore(type) != null;
  31:         }
  32:     }

Tying it all together

In the startup of our application (in my case, Application_Start in global.asax) I first bootstrap my container and then ask it for an implementation of CreateDynamicDataStores. This class takes two parameters in it’s constructor. The first is a class that implements DynamicDataStoreFactory which  StructureMap will resolve to use DynamicDataStoreFactory.Instance. The second parameter is a list of classes implementing ISpecifyTypeForDynamicDataStore. Since we added all types that implements that interface StructureMap is smart enough to send all implementations to the method. For more info on StructureMap check out my introduction.

   1: protected void Application_Start(Object sender, EventArgs e)
   2: {
   3:     EPiServer.Configuration.StructureMap.Bootstrapper.BootstrapStructureMap(ObjectFactory.Container);
   4:     ObjectFactory.GetInstance<CreateDynamicDataStores>().CreateStoreIfItDoesNotExist();
   5:     XFormControl.ControlSetup += new EventHandler(XForm_ControlSetup);
   6: }

Testing the CreateDynamicDataStores

Like my boulder climbing friend Niklas has blogged about testing code that interacts with DDS is a breath of fresh air. For more info about what Moq is or a more general description of working with unit test s(in a EPiServer centered direction) please read my previous blog post.

For my class CreateDynamicDataStores I’ve created the following specifications:

image

These specification are written in MSpec (read this post by Joel for more info on MSpec) and looks like this:

For the case were “when a type that does not have a data store is sent to create dynamic data stores” we want to make sure that if the store does not exist for a specific type it’s created for that same type. What this means in terms of the DynamicDataStoreFactory is that it should not return anything (eg null) when loaded with the type and then we need to verify that the method Create is called with the type as a parameter.

First we establish our context (sort of the Arrange)

   1: Establish context = () =>
   2: {
   3:     _types = new[] {typeof (string)};
   4:     _typeList = ListISpecifyTypeForDynamicDataStoreFactory.CreateListoOfMocksForTypes(_types);
   5:     
   6:     _dynamicDataStoreFactory = new Mock<DynamicDataStoreFactory>();
   7:     _dynamicDataStoreFactory
   8:         .Setup(x => x.GetStore(_types[0]))
   9:         .Returns((DynamicDataStore)null);
  10:  
  11:     _createDynamicDataStores = new CreateDynamicDataStores(_dynamicDataStoreFactory.Object, _typeList);
  12: };

Then we perform an action (the Act), in this case running the method CreateStoreIfItDoesNotExist

   1: Because of =
   2:             () => _createDynamicDataStores.CreateStoreIfItDoesNotExist();

Now we need to check our mocks to verify the expected behaviors.

It should have tried to load the store for the first type in the array

   1: It should_try_to_load_the_store =
   2:     () => _dynamicDataStoreFactory.Verify(x => x.GetStore(_types[0]));

Since this should return null is should also try to create the store for the very same type

   1: It should_create_a_store_for_the_type =
   2:     () => _dynamicDataStoreFactory.Verify(x => x.CreateStore(_types[0]));

(Tests for the other scenario are more or less exactly the same. Only difference is that the GetStore should return a store and we need to verify that the CreateStore is not called).

Still awake? If so, I want to wish you an awesome Christmas!

Dec 21, 2010

Comments

Please login to comment.
Latest blogs
Opti ID overview

Opti ID allows you to log in once and switch between Optimizely products using Okta, Entra ID, or a local account. You can also manage all your use...

K Khan | Jul 26, 2024

Getting Started with Optimizely SaaS using Next.js Starter App - Extend a component - Part 3

This is the final part of our Optimizely SaaS CMS proof-of-concept (POC) blog series. In this post, we'll dive into extending a component within th...

Raghavendra Murthy | Jul 23, 2024 | Syndicated blog

Optimizely Graph – Faceting with Geta Categories

Overview As Optimizely Graph (and Content Cloud SaaS) makes its global debut, it is known that there are going to be some bugs and quirks. One of t...

Eric Markson | Jul 22, 2024 | Syndicated blog

Integration Bynder (DAM) with Optimizely

Bynder is a comprehensive digital asset management (DAM) platform that enables businesses to efficiently manage, store, organize, and share their...

Sanjay Kumar | Jul 22, 2024

Frontend Hosting for SaaS CMS Solutions

Introduction Now that CMS SaaS Core has gone into general availability, it is a good time to start discussing where to host the head. SaaS Core is...

Minesh Shah (Netcel) | Jul 20, 2024

Optimizely London Dev Meetup 11th July 2024

On 11th July 2024 in London Niteco and Netcel along with Optimizely ran the London Developer meetup. There was an great agenda of talks that we put...

Scott Reed | Jul 19, 2024