I want to avoid cyclic dependency in this schema:
DbRepository
needs IUserDbEntityFactory
to create User
entity which needs IUserPublishedInfoInitializer
to create UserPublishedInfo
on request. And UserPublishedInfoInitializer
itself needs IDbRepository
to check whether the user is currently present in cache and active to set IsOnline
property on UserPublishedInfo
.
Both CreateUser
and TryGetCachedUser
methods use the same internal things like caching and locks inside DbRepository
.
User
is a an aggregation root db entity without interface.
DbRepository
requires IUserDbEntityFactory
which requires IUserPublishedInfoInitializer
to construct User
and makes cyclic dependency back to DbRepository
. I usually use constructor dependency injection but in this case it won't work because of cyclic dependency so this is what the question is about.
Also I don't want to move MakePublishedInfo
out of User
because it's actually an implicit conversation in C# and is used very frequently in the code.
And passing IDbRepository
to IUserPublishedInfoInitializer.Init
as an argument is neither what I want because why should this implementation depend on what's using it? This breaks encapsulation.
On the schema only User
and UserPublishedInfo
are dynamically created objects (others are created at startup).
Should I change this design and what it should look like?
Best Answer
I would remove the Dependency of IUserPublishedInfoInitializer on IDbRepository. Instead inject this as a construction parameter into the concrete UserPublishedInfoInitializer.
your dependency graph then looks like
edit --
OK you just need a special constructor on DbRepository or child class
if you still want to it via DI you could have a DbRepositoryFactory to do the same thing
However, I'm not sure injecting MORE things really helps with your core problem which is having the User object being uncreateable without a repository.
hard to say without seeing the whole problem but, just from the naming it seems like UserPublishedInfoInitializer is unnecessary, your repository could take responsibility for creating the UserPublishedInfo object if User is effectivly the aggregate root and always has a UserPublishedInfo property