In my project, I have the following PageCache
entity, which is being stored in RavenDB:
public class PageCache
{
private readonly IHtmlDocumentHelper htmlDocumentHelper;
public string Id { get; set; }
public string Url { get; set; }
public PageCache(IHtmlDocumentHelper htmlDocumentHelper, string url)
{
this.htmlDocumentHelper = htmlDocumentHelper;
this.Url = url;
}
}
I am using Castle Windsor to inject the IHtmlDocumentHelper
implementation at runtime. This member is used in methods defined inside the PageCache
class, which I stripped from the above snippet for the sake of simplicity.
When I create a PageCache
object using the constructor, everything works fine. But elsewhere in my code, I load PageCache
objects back from RavenDB:
public PageCache GetByUrl(string url)
{
using (var session = documentStore.OpenSession())
{
return session.Query<PageCache>()
.Where(x => x.Url == url)
.FirstOrDefault();
}
}
My issue is that the objects I get back from RavenDB don't have the htmlDocumentHelper
member set, rendering the PageCache
methods that depend on it unuseable.
In other words: when I load objects back from documents stored in RavenDB, it won't use my constructor to build the objects, thus not initializing the private members through constructor injection.
Am I doing something wrong here? How would you solve such an issue?
I ended up using the solution proposed by Ayende below. The circular dependency issue I mentioned in the comments only appeared when I registered the DocumentStore
in Windsor with UsingFactoryMethod()
. The issue strangely disappeared when I used Windsor's DependsOn()
and OnCreate()
to configure and initialize the DocumentStore
directly inside the Register()
.
My container is now being initialized as follows:
WindsorContainer container = new WindsorContainer();
container.Register(
// Register other classes, such as repositories and services.
// Stripped for the sake of clarity.
// ...
// Register the CustomJsonConverter:
Component.For<CustomJsonConverter>().ImplementedBy<CustomJsonConverter>(),
// The following approach resulted in an exception related to the circular
// dependencies issue:
Component.For<IDocumentStore>().UsingFactoryMethod(() =>
Application.InitializeDatabase(container.Resolve<CustomJsonConverter>()))
// Oddly enough, the following approach worked just fine:
Component.For<IDocumentStore>().ImplementedBy<DocumentStore>()
.DependsOn(new { Url = @"http://localhost:8080" })
.OnCreate(new Action<IDocumentStore>(store =>
store.Conventions.CustomizeJsonSerializer = serializer =>
serializer.Converters.Add(container.Resolve<CustomJsonConverter>())))
.OnCreate(new Action<IDocumentStore>(store =>
store.Initialize()))
.OnDestroy(new Action<IDocumentStore>(store =>
store.Dispose()))
);
Although it seems to be working fine, I feel odd having to call container.Resolve<CustomJsonConverter>()
from inside the container.Register()
method.
Is this a legal approach to register the dependencies?
Christian, We can't use your ctor, we don't know what to put in there.
Instead, you can use this technique to tell RavenDB how to create your objects: http://james.newtonking.com/projects/json/help/CustomCreationConverter.html
Then you can wire this in using documentStore.Conventison.CustomizeSerializer