ARTICLE
The Scoped Lifestyle
From Dependency Injection, Principles, Practices, and Patterns
by Steven van Deursen and Mark Seemann
This articles explains the Scoped Lifestyle: what it is and when you might want to use it.
_________________________________________________________________
Take 37% off Dependency Injection, Principles, Practices, and Patterns. Just enter code fccseemann into the discount code box at checkout at manning.com.
_________________________________________________________________
As users of a web application, we’d like a response from the application as quickly as possible, even when other users are accessing the system at the same time. We don’t want our request to be put on a queue together with all the other users’ requests. We might have to wait an inordinate amount of time for a response if there are many requests ahead of ours. To address this issue, web applications handle requests concurrently.
Because of concurrency, Dependencies that aren’t thread-safe can’t be used as Singletons. On the other hand, using them as Transients can be inefficient or even downright problematic if you need to share a Dependency between different consumers within the same request.
This leads to the concept of a Scoped Lifestyle, where you decide to reuse instances within a given scope.
DEFINITION: Scoped Dependencies behave like Singleton Dependencies within a single, well-defined scope or request but aren’t shared across scopes. Each scope has its own cache of associated Dependencies.
The Scoped Lifestyle makes sense for long-running applications that are tasked with processing operations that need to run with some degree of isolation. Isolation is required when these operations are processed in parallel, or when each operation contains its own state. Web applications are a great example of where the Scoped Lifestyle works well, because web applications typically process requests in parallel, and those requests typically contain some mutable state that’s specific to the request. But even if a web application starts some background operation that isn’t related to a web request, the Scoped Lifestyle is valuable. Even these background operations can typically be mapped to the concept of a request.
Example: Composing a long-running application using a Scoped IUserContext
As with all Lifestyles, you can mix the Scoped Lifestyle with others so that, for example, some Dependencies are configured as Singletons, and others are shared per request.
In this example, you’ll see how to compose a long-running web application, with Scoped IUserContext
Dependency.
Listing 1 Resolving Scoped IUserContext
instances
private HomeController CreateHomeController()
{
IUserContext context = new AspNetUserContextAdapter(); ❶
return
new HomeController(
new ProductService(
new SqlProductRepository(this.connStr),
context, ❷
new SqlUserRepository(
this.connStr,
context))); ❷
}
❶ Create Scoped Dependency
❷ Inject the Scoped Dependency into the Transient object graph
In this example, the CreateHomeController
method acts as the application's Composer. It creates a new object graph on every call. This call would typically be called once for every request for the application's home page. During the call, however, the method creates only one instance of the AspNetUserContextAdapter
. This AspNetUserContextAdapter
instance is reused throughout the graph and injected in both the ProductService
and the SqlUserRepository
. That single AspNetUserContextAdapter
is reused for the duration of the request, but other requests get their own instance.
Whereas a Transient Lifestyle implies that every consumer receives a private instance of a Dependency, a Scoped Lifestyle ensures that all consumers of all resolved graphs for that scope get the same instance.
That’s all for this article. If you want to learn more about the book, check it out on liveBook here.
You can also see other articles on common DI-related topics:
Originally published at https://freecontent.manning.com.