Try our conversational search powered by Generative AI!

Stefan Forsberg
Dec 21, 2010
  4429
(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
The A/A Test: What You Need to Know

Sure, we all know what an A/B test can do. But what is an A/A test? How is it different? With an A/B test, we know that we can take a webpage (our...

Lindsey Rogers | Apr 15, 2024

.Net Core Timezone ID's Windows vs Linux

Hey all, First post here and I would like to talk about Timezone ID's and How Windows and Linux systems use different IDs. We currently run a .NET...

sheider | Apr 15, 2024

What's new in Language Manager 5.3.0

In Language Manager (LM) version 5.2.0, we added an option in appsettings.json called TranslateOrCopyContentAreaChildrenBlockForTypes . It does...

Quoc Anh Nguyen | Apr 15, 2024

Optimizely Search & Navigation: Boosting in Unified Search

In the Optimizely Search & Navigation admin view, administrators can set a certain weight of different properties (title, content, summary, or...

Tung Tran | Apr 15, 2024