2

My company's MVC Solution uses an IOC Container to inject the Caching/Repository layer into the controllers. This is incredibly expensive as currently we're generating new classes each time we create the controller (can amount to thousands of objects as the caching layer objects have refs to the repo layer - and all those classes get created). I know that the Singleton pattern is heavily disliked for many reasons (see Why Singletons are Evil) but is there any reason not to set the IOC Container to singleton for the caching/repo layer objects?

Thanks.

Alex Krupka
  • 710
  • 9
  • 20

2 Answers2

6

You are mixing things up. The Singleton design pattern is something completely different than the Singleton lifestyle that DI libraries use.

With the Singleton pattern you typically define a public static readonly field on a concrete class that holds the sole instance of that class; this instance is created by the class itself and the whole application can access that readonly field. E.g.:

public static class CarEngine
{
    public static readonly CarEngine Instance = new CarEngine();

    // class methods
}

With the Singleton lifestyle, you instruct your container that it should create just a single instance during the lifetime of that container and reuse it.

The Singleton design pattern is a problem because it forces consumers to take a hard dependency on a concrete class (A Dependency Inversion Principle violation) and since that concrete class is internally in control over the creation, it becomes much harder to use a fake implementation during testing. Besides this, since consumers don't have a constructor that requires that class as dependency, to effectively make the dependency hidden from people who read the code, create tests, and from tools as DI libraries who can do object graph analysis for you. The article you point at actually does actually does a really good job in explaining why the Singleton design pattern is bad.

The article however never really mentions the Singleton lifestyle, but since it talks about how Singleton design pattern hides dependencies, it implies that dependencies should be injected. And since you want some classes to have one instance and inject them through the constructor, the Singleton lifestyle is the actual solution to this problem.

The Singleton lifestyle solves these problems, because you move the responsibility of creating that single instance from the concrete class, which allows consumers to depend on an abstraction instead in their constructor, which makes the dependency visible and the code more testable.

So there's nothing wrong with making your registrations singleton. As a matter of fact, I think you should prefer making as many registrations as possible singleton, because this prevents a large set of problems that developers typically face when practicing dependency injection. By making every component immutable and stateless, they become easier to reason about and you prevent yourself from accidentally injecting runtime data into a component, which is bad practice. Another common pitfall with DI is Captive Dependencies, which means that a component depends on another component that should have a shorter lifestyle. If you make all components immutable, stateless and singleton, the problem of Captive Dependencies goes away, because singleton components can safely depend on each other.

Of course you will always need runtime data in your components (such as things like request data, O/RM contexts and such), but these can be requested at runtime by injecting a provider or simple Func<DbContext> into adapter implementations that abstract 3rd party tools away from your application (which is good practice if you follow SOLID). This Stackoverflow answer goes into more detail about this.

Steven
  • 166,672
  • 24
  • 332
  • 435
1

First of all. .NET can create millions of objects in very little time. Using a IoC is a bit slower, but not that slow. A benchmark tests a few IoCs and they resolve 500 000 objects in a few seconds.

My company's MVC Solution uses an IOC Container to inject the Caching/Repository layer into the controllers. This is incredibly expensive as currently we're generating new classes each time we create the controller (can amount to thousands of objects as the caching layer objects have refs to the repo layer - and all those classes get created).

Are you saying that the cache is regenerated on every request? Then you have done something wrong.

A cache is typically a single instance (i.e. created once by the container and then the same instance is returned every time something resolves the cache).

The repository must be per request since it requires a database connection and/or transaction. And you want to keep those short lived.

So the problem isn't the IoC but how you have designed the interaction between the cache, the repositories and the cached objects.

Sorry for not explaining clearly. We use dapper for the Repo layer so the Repo classes only create a connection to the Database when a method is called. The cache is using HTTPCache and Redis, but we have Cache Repo Classes that handle the logic (if in cache..) If each user call is creating thousands of duplicate objects that seems like it can tax the servers resources unnecessarily

I'm still not with you. imho caching entities is an implementation detail in the persistence layer.

  1. Your repository is scoped (create one object per http request) or transient (new object every time)
  2. Your cache is SingleInstance (create on object per application lifetime)
  3. Your repository holds a reference to the cache (constructor injection)
  4. When your repository fails to find the object in the cache it queries the database

Why should the cache only be used in the repositories (other than being a persistence implementation detail)? Because it reduces complexity since the repositories are the only classes in the system that are aware of ALL entity modifications without extra logic.

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • Sorry for not explaining clearly. We use dapper for the Repo layer so the Repo classes only create a connection to the Database when a method is called. The cache is using HTTPCache and Redis, but we have Cache Repo Classes that handle the logic (if in cache..) If each user call is creating thousands of duplicate objects that seems like it can tax the servers resources unnecessarily – Alex Krupka May 19 '16 at 20:27