Dependency Injection Principles, Practices, and Patterns

Book description

Dependency Injection Principles, Practices, and Patterns teaches you to use DI to reduce hard-coded dependencies between application components. You'll start by learning what DI is and what types of applications will benefit from it. Then, you'll work through concrete scenarios using C# and the .NET framework to implement DI in your own projects. As you dive into the thoroughly-explained examples, you'll develop a foundation you can apply to any of the many DI libraries for .NET and .NET Core.

About the Technology
Dependency Injection (DI) is a great way to reduce tight coupling between software components. Instead of hard-coding dependencies, such as specifying a database driver, you make those connections through a third party. Central to application frameworks like ASP.NET Core, DI enables you to better manage changes and other complexity in your software.

About the Book
Dependency Injection Principles, Practices, and Patterns is a revised and expanded edition of the bestselling classic Dependency Injection in .NET. It teaches you DI from the ground up, featuring relevant examples, patterns, and anti-patterns for creating loosely coupled, well-structured applications. The well-annotated code and diagrams use C# examples to illustrate principles that work flawlessly with modern object-oriented languages and DI libraries.

What's Inside
  • Refactoring existing code into loosely coupled code
  • DI techniques that work with statically typed OO languages
  • Integration with common .NET frameworks
  • Updated examples illustrating DI in .NET Core


About the Reader
For intermediate OO developers.

About the Authors
Mark Seemann is a programmer, software architect, and speaker who has been working with software since 1995, including six years with Microsoft. Steven van Deursen is a seasoned .NET developer and architect, and the author and maintainer of the Simple Injector DI library.

Quotes
Actually three books in one: a really good introduction to DI in .NET, an even better one to DI in general, and an absolutely excellent introduction to OO principles and software design.
- Mikkel Arentoft, Danske Bank

This book is a masterpiece. It’s amazing and fundamental for every software developer who wants to write solid and correct code.
- Emanuele Origgi, Funambol

A marvelous, clear, and exhaustive journey into all aspects of DI in .NET, with very focused and complete real world examples.
- Pasquale Zirpoli, MIED Open Source Initiative

Publisher resources

View/Submit Errata

Table of contents

  1. Dependency Injection
    1. Principles, Practices, and Patterns
  2. brief contents
  3. contents
  4. Praise for the First Edition
  5. front matter
    1. preface
    2. acknowledgments
    3. about this book
      1. Who should read this book?
      2. Roadmap
      3. Code conventions and downloads
      4. liveBook discussion forum
    4. about the authors
    5. about the cover illustration
  6. Part 1. Putting Dependency Injection on the map
  7. 1 The basics of Dependency Injection: What, why, and how
    1. 1.1 Writing maintainable code
      1. 1.1.1 Common myths about DI
      2. 1.1.2 Understanding the purpose of DI
    2. 1.2 A simple example: Hello DI!
      1. 1.2.1 Hello DI! code
      2. 1.2.2 Benefits of DI
    3. 1.3 What to inject and what not to inject
      1. 1.3.1 Stable Dependencies
      2. 1.3.2 Volatile Dependencies
    4. 1.4 DI scope
      1. 1.4.1 Object Composition
      2. 1.4.2 Object Lifetime
      3. 1.4.3 Interception
      4. 1.4.4 DI in three dimensions
    5. 1.5 Conclusion
    6. Summary
  8. 2 Writing tightly coupled code
    1. 2.1 Building a tightly coupled application
      1. 2.1.1 Meet Mary Rowan
      2. 2.1.2 Creating the data layer
      3. 2.1.3 Creating the domain layer
      4. 2.1.4 Creating the UI layer
    2. 2.2 Evaluating the tightly coupled application
      1. 2.2.1 Evaluating the dependency graph
      2. 2.2.2 Evaluating composability
    3. 2.3 Analysis of missing composability
      1. 2.3.1 Dependency graph analysis
      2. 2.3.2 Data access interface analysis
      3. 2.3.3 Miscellaneous other issues
    4. 2.4 Conclusion
    5. Summary
  9. 3 Writing loosely coupled code
    1. 3.1 Rebuilding the e-commerce application
      1. 3.1.1 Building a more maintainable UI
      2. 3.1.2 Building an independent domain model
      3. 3.1.3 Building a new data access layer
      4. 3.1.4 Implementing an ASP.NET Core–specific IUserContext Adapter
      5. 3.1.5 Composing the application in the Composition Root
    2. 3.2 Analyzing the loosely coupled implementation
      1. 3.2.1 Understanding the interaction between components
      2. 3.2.2 Analyzing the new dependency graph
    3. Summary
  10. Part 2. Catalog
  11. 4 DI patterns
    1. 4.1 Composition Root
      1. 4.1.1 How Composition Root works
      2. 4.1.2 Using a DI Container in a Composition Root
      3. 4.1.3 Example: Implementing a Composition Root using Pure DI
      4. 4.1.4 The apparent dependency explosion
    2. 4.2 Constructor Injection
      1. 4.2.1 How Constructor Injection works
      2. 4.2.2 When to use Constructor Injection
      3. 4.2.3 Known use of Constructor Injection
      4. 4.2.4 Example: Adding currency conversions to the featured products
      5. 4.2.5 Wrap-up
    3. 4.3 Method Injection
      1. 4.3.1 How Method Injection works
      2. 4.3.2 When to use Method Injection
      3. 4.3.3 Known use of Method Injection
      4. 4.3.4 Example: Adding currency conversions to the ProductEntity
    4. 4.4 Property Injection
      1. 4.4.1 How Property Injection works
      2. 4.4.2 When to use Property Injection
      3. 4.4.3 Known uses of Property Injection
      4. 4.4.4 Example: Property Injection as an extensibility model of a reusable library
    5. 4.5 Choosing which pattern to use
    6. Summary
  12. 5 DI anti-patterns
    1. 5.1 Control Freak
      1. 5.1.1 Example: Control Freak through newing up Dependencies
      2. 5.1.2 Example: Control Freak through factories
      3. 5.1.3 Example: Control Freak through overloaded constructors
      4. 5.1.4 Analysis of Control Freak
    2. 5.2 Service Locator
      1. 5.2.1 Example: ProductService using a Service Locator
      2. 5.2.2 Analysis of Service Locator
    3. 5.3 Ambient Context
      1. 5.3.1 Example: Accessing time through Ambient Context
      2. 5.3.2 Example: Logging through Ambient Context
      3. 5.3.3 Analysis of Ambient Context
    4. 5.4 Constrained Construction
      1. 5.4.1 Example: Late binding a ProductRepository
      2. 5.4.2 Analysis of Constrained Construction
    5. Summary
  13. 6 Code smells
    1. 6.1 Dealing with the Constructor Over-injection code smell
      1. 6.1.1 Recognizing Constructor Over-injection
      2. 6.1.2 Refactoring from Constructor Over-injection to Facade Services
      3. 6.1.3 Refactoring from Constructor Over-injection to domain events
    2. 6.2 Abuse of Abstract Factories
      1. 6.2.1 Abusing Abstract Factories to overcome lifetime problems
      2. 6.2.2 Abusing Abstract Factories to select Dependencies based on runtime data
    3. 6.3 Fixing cyclic Dependencies
      1. 6.3.1 Example: Dependency cycle caused by an SRP violation
      2. 6.3.2 Analysis of Mary’s Dependency cycle
      3. 6.3.3 Refactoring from SRP violations to resolve the Dependency cycle
      4. 6.3.4 Common strategies for breaking Dependency cycles
      5. 6.3.5 Last resort: Breaking the cycle with Property Injection
    4. Summary
  14. Part 3. Pure DI
  15. 7 Application composition
    1. 7.1 Composing console applications
      1. 7.1.1 Example: Updating currencies using the UpdateCurrency program
      2. 7.1.2 Building the Composition Root of the UpdateCurrency program
      3. 7.1.3 Composing object graphs in CreateCurrencyParser
      4. 7.1.4 A closer look at UpdateCurrency’s layering
    2. 7.2 Composing UWP applications
      1. 7.2.1 UWP composition
      2. 7.2.2 Example: Wiring up a product-management rich client
      3. 7.2.3 Implementing the Composition Root in the UWP application
    3. 7.3 Composing ASP.NET Core MVC applications
      1. 7.3.1 Creating a custom controller activator
      2. 7.3.2 Constructing custom middleware components using Pure DI
    4. Summary
  16. 8 Object lifetime
    1. 8.1 Managing Dependency Lifetime
      1. 8.1.1 Introducing Lifetime Management
      2. 8.1.2 Managing lifetime with Pure DI
    2. 8.2 Working with disposable Dependencies
      1. 8.2.1 Consuming disposable Dependencies
      2. 8.2.2 Managing disposable Dependencies
    3. 8.3 Lifestyle catalog
      1. 8.3.1 The Singleton Lifestyle
      2. 8.3.2 The Transient Lifestyle
      3. 8.3.3 The Scoped Lifestyle
    4. 8.4 Bad Lifestyle choices
      1. 8.4.1 Captive Dependencies
      2. 8.4.2 Using Leaky Abstractions to leak Lifestyle choices to consumers
      3. 8.4.3 Causing concurrency bugs by tying instances to the lifetime of a thread
    5. Summary
  17. 9 Interception
    1. 9.1 Introducing Interception
      1. 9.1.1 Decorator design pattern
      2. 9.1.2 Example: Implementing auditing using a Decorator
    2. 9.2 Implementing Cross-Cutting Concerns
      1. 9.2.1 Intercepting with a Circuit Breaker
      2. 9.2.2 Reporting exceptions using the Decorator pattern
      3. 9.2.3 Preventing unauthorized access to sensitive functionality using a Decorator
    3. Summary
  18. 10 Aspect-Oriented Programming by design
    1. 10.1 Introducing AOP
    2. 10.2 The SOLID principles
      1. 10.2.1 Single Responsibility Principle (SRP)
      2. 10.2.2 Open/Closed Principle (OCP)
      3. 10.2.3 Liskov Substitution Principle (LSP)
      4. 10.2.4 Interface Segregation Principle (ISP)
      5. 10.2.5 Dependency Inversion Principle (DIP)
      6. 10.2.6 SOLID principles and Interception
    3. 10.3 SOLID as a driver for AOP
      1. 10.3.1 Example: Implementing product-related features using IProductService
      2. 10.3.2 Analysis of IProductService from the perspective of SOLID
      3. 10.3.3 Improving design by applying SOLID principles
      4. 10.3.4 Adding more Cross-Cutting Concerns
      5. 10.3.5 Conclusion
    4. Summary
  19. 11 Tool-based Aspect-Oriented Programming
    1. 11.1 Dynamic Interception
      1. 11.1.1 Example: Interception with Castle Dynamic Proxy
      2. 11.1.2 Analysis of dynamic Interception
    2. 11.2 Compile-time weaving
      1. 11.2.1 Example: Applying a transaction aspect using compile-time weaving
      2. 11.2.2 Analysis of compile-time weaving
    3. Summary
  20. Part 4. DI Containers
  21. 12 DI Container introduction
    1. 12.1 Introducing DI Containers
      1. 12.1.1 Exploring containers’ Resolve API
      2. 12.1.2 Auto-Wiring
      3. 12.1.3 Example: Implementing a simplistic DI Container that supports Auto-Wiring
    2. 12.2 Configuring DI Containers
      1. 12.2.1 Configuring containers with configuration files
      2. 12.2.2 Configuring containers using Configuration as Code
      3. 12.2.3 Configuring containers by convention using Auto-Registration
      4. 12.2.4 Mixing and matching configuration approaches
    3. 12.3 When to use a DI Container
      1. 12.3.1 Using third-party libraries involves costs and risks
      2. 12.3.2 Pure DI gives a shorter feedback cycle
      3. 12.3.3 The verdict: When to use a DI Container
    4. Summary
  22. 13 The Autofac DI Container
    1. 13.1 Introducing Autofac
      1. 13.1.1 Resolving objects
      2. 13.1.2 Configuring the ContainerBuilder
    2. 13.2 Managing lifetime
      1. 13.2.1 Configuring instance scopes
      2. 13.2.2 Releasing components
    3. 13.3 Registering difficult APIs
      1. 13.3.1 Configuring primitive Dependencies
      2. 13.3.2 Registering objects with code blocks
    4. 13.4 Working with multiple components
      1. 13.4.1 Selecting among multiple candidates
      2. 13.4.2 Wiring sequences
      3. 13.4.3 Wiring Decorators
      4. 13.4.4 Wiring Composites
    5. Summary
  23. 14 The Simple Injector DI Container
    1. 14.1 Introducing Simple Injector
      1. 14.1.1 Resolving objects
      2. 14.1.2 Configuring the container
    2. 14.2 Managing lifetime
      1. 14.2.1 Configuring Lifestyles
      2. 14.2.2 Releasing components
      3. 14.2.3 Ambient scopes
      4. 14.2.4 Diagnosing the container for common lifetime problems
    3. 14.3 Registering difficult APIs
      1. 14.3.1 Configuring primitive Dependencies
      2. 14.3.2 Extracting primitive Dependencies to Parameter Objects
      3. 14.3.3 Registering objects with code blocks
    4. 14.4 Working with multiple components
      1. 14.4.1 Selecting among multiple candidates
      2. 14.4.2 Wiring sequences
      3. 14.4.3 Wiring Decorators
      4. 14.4.4 Wiring Composites
      5. 14.4.5 Sequences are streams
    5. Summary
  24. 15 The Microsoft.Extensions.DependencyInjection DI Container
    1. 15.1 Introducing Microsoft.Extensions.DependencyInjection
      1. 15.1.1 Resolving objects
      2. 15.1.2 Configuring the ServiceCollection
    2. 15.2 Managing lifetime
      1. 15.2.1 Configuring Lifestyles
      2. 15.2.2 Releasing components
    3. 15.3 Registering difficult APIs
      1. 15.3.1 Configuring primitive Dependencies
      2. 15.3.2 Extracting primitive Dependencies to Parameter Objects
      3. 15.3.3 Registering objects with code blocks
    4. 15.4 Working with multiple components
      1. 15.4.1 Selecting among multiple candidates
      2. 15.4.2 Wiring sequences
      3. 15.4.3 Wiring Decorators
      4. 15.4.4 Wiring Composites
    5. Summary
  25. glossary
  26. resources
  27. Index
  28. Lists of Figures, Tables and Listings
    1. List of Illustrations
    2. List of Tables
    3. List of Listings

Product information

  • Title: Dependency Injection Principles, Practices, and Patterns
  • Author(s): Mark Seemann, Steven van Deursen
  • Release date: March 2019
  • Publisher(s): Manning Publications
  • ISBN: 9781617294730