RavenDB - Image Gallery Project (III) - The Application Lifecycle
The code for this and all other entries can be found here: http://github.com/robashton/RavenGallery/
As discussed in the previous entry, I have decided to host RavenDB within the application itself, this is a decision that lends itself very easily to the early stages of a development project against RavenDB, as there is no need to remember to run RavenDB before running the application, and it is a decision that providing you write your code properly can be changed later on in development when it becomes useful to have RavenDB running on another server or just as a separate process.
Before writing any code, we have to understand the basic components at play when communicating with RavenDB.
- IDocumentStore
- This is the main port of call for communicating with a RavenDB server
- This is also the main port of call for starting up a RavenDB server if running locally (DocumentStore)
- One of these should exist per application – IE, create on start-up and persist
- IDocumentSession
- This is created via IDocumentStore and provides interfaces for querying the document store
- This controls the unit of work, tracks loaded documents, keeps a cache etc
- This should be created per-unit-of-work (Typically one per HTTP request, or one per transaction)
- NB: Whilst RavenDB supports transactions across requests, typically we avoid this and try to commit all changes once per unit of work
On start-up
So, on start-up we need to create a document store and make that available for creating document sessions when necessary (and maybe other purposes).
This is what I’ve come up with:
Bootstrapper.cs
1: public static class Bootstrapper
2: {
3: public static void Startup()
4: {
5: var documentStore = new EmbeddableDocumentStore
6: {
7: Configuration = new RavenConfiguration
8: {
9: DataDirectory = "App_Data\\RavenDB",
10: }
11: };
12: documentStore.Initialize();
13:
14: ObjectFactory.Initialize(config =>
15: {
16: config.AddRegistry(new CoreRegistry(documentStore));
17: });
18: }
19: }
This is invoked from Global.asax.cs via Application_Start – we create the DocumentStore and pass it into a StructureMap registry which then sets up the container. If I wanted to switch to a different mechanism for dealing with RavenDB I could change it here and the rest of my application wouldn’t be any the wiser. I could even load the settings from a file here, but I’m not going to – so there.
Inside CoreRegistry.cs we have
1: public class CoreRegistry : Registry
2: {
3: public CoreRegistry(IDocumentStore documentStore)
4: {
5: For<IDocumentStore>().Use(documentStore);
6: }
7: }
Per request
Until we find a reason not to, we will create RavenDB sessions per request and secretly store them in the HttpContext.Items collection so they can be used through-out the rest of the request, of course we’ll use StructureMap to manage that for us.
CoreRegistry.cs now looks like this:
1: public CoreRegistry(IDocumentStore documentStore)
2: {
3: For<IDocumentStore>().Use(documentStore);
4: For<IDocumentSession>()
5: .HttpContextScoped()
6: .Use(x =>
7: {
8: var store = x.GetInstance<IDocumentStore>();
9: return store.OpenSession();
10: });
11: }
Of course this is leaking sessions because StructureMap won’t dispose of any of our created sessions unless we tell it to, so into Global.asax.cs I go once more and add the following line:
1: protected void Application_EndRequest()
2: {
3: ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
4: }
This will do for now, I could have done this using a HttpModule or whatever I preferred, but that gets the concepts across.
In the next entry I’ll give a refresh on how documents are created/modified/queried in order to lay the groundwork for the structure of the rest of the application.