Dependency Injection in .NET applications
-
Upload
babak-naffas -
Category
Software
-
view
428 -
download
4
Transcript of Dependency Injection in .NET applications
![Page 1: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/1.jpg)
Dependency Injection with .NET
-OR-
So you’ve decided to finally inject your dependencies
-OR-Let’s test production scenarios so it
doesn’t break
![Page 2: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/2.jpg)
Overview
• What is DI?
• Why use DI?
• Where to use DI?
• How to do DI?
• C#, Legacy Code, and DI
– Interfaces, and Singletons, and Mocks, oh my!
![Page 3: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/3.jpg)
What is Dependency Injection
• A software design pattern that implements inversion of control for resolving dependencies. A dependency is an object that can be used (a service). An injection is the passing of a dependency to a dependent object (a client) that would use it.– Wikipedia
AppIoCDependency
ConcreteImplementation
ConcreteImplementation
ConcreteImplementation
![Page 4: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/4.jpg)
Dependency Inject – An Example
• Legacy code w/o DI
public class ReviewManager{
public ElasticSearchBackedReviewRepository ReviewsRepo
{get; set;}
public void GetReviewsByMovie( int movieId){
return ElasticSearchBackedReviewRepository.GetReviews(movieId);
}
}
• Legacy code w/o DI
public class ReviewManager{
public IReviewRepository ReviewsRepo {get; set;}
Public ReviewManager( IReviewRepository repo ){
ReviewsRepo = repo;
}
public void GetReviewsByMovie( int movieId){
return ReviewsRepo.GetReviews(moviedId);
}
}
AppIoCDependency
ConcreteImplementation
ConcreteImplementation
ConcreteImplementation
![Page 5: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/5.jpg)
Why Interfaces?
• Develop against a contract
– Business logic isn’t changed as new implementations are introduced
• Moq (for unit tests) requires interfaces or virtual methods.
• All wiring for dependencies can be performed in a centralized location
![Page 6: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/6.jpg)
Why Mocking?
• Allows testing any use case without the need for test data
– Mock a response that returns the use case you are testing (as opposed to test data in the DB)
– Null return values
– Timeout (web service clients)
– 0 reviews, 1 review, 10000 reviews
![Page 7: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/7.jpg)
When? Architecture Boundaries
App (Front End)App (Business Logic)
DB 1
DB 2
Service 1
Service 1
Service 1
Any time the app reaches out for data is a good candidate for dependency injection.
In this scenario, the clients we use to wrap the 2 databases and the 3 services would each implement an interface that could be mocked for unit tests
![Page 8: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/8.jpg)
When? Responsibility Boundaries
• Fandango Desktop/Mobile Web
– Reviews (Direct DB calls, Elastic search service)
– Movies (DB calls, movie service)
– Theaters (DB calls, Commerce service, old service, new API)
![Page 9: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/9.jpg)
DI via Delegates
• Initial Effort is low– No extra frameworks– unit test can define the mocked method
• Subsequent efforts are O(N)– One change per new mocked method
• Pros– Methods can be incorporated one at a time
• Cons– Each new method will require its own delegate and
new wiring.
![Page 10: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/10.jpg)
DI via Mock POCOs
• Initial Effort is medium– New class for each mock– Logic for mock states
• Subsequent efforts– Potential for new forks (and bugs) in mock POCO logic for
each use case
• Pros– Don’t need to learn a new framework.
• Cons– Supporting all use cases increases potential for bugs in the
mocks.– Some dependencies can’t be mocked
1
1 – With Moq, you can only mock methods defined in an interface or virtual methods.
![Page 11: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/11.jpg)
DI with Mocks (Moq)
• Initial Effort is high– Each unit test use case requires its own moq wrapper
per dependency
• Subsequent changes– Only changes to the contract require modifications to
your mocks
• Pros– Each tests clearly identifies its assumptions
• Cons– Lots of unit test code will just be setting up the
dependency
![Page 12: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/12.jpg)
Legacy Code: Static Methods
• Interfaces can’t have static methods
• Convert static methods to instance methods that conform to the (new) interface with a Singleton to expose the static instance.
![Page 13: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/13.jpg)
ScenarioProduction issue with unknown cause
• Scenario in production we can’t reproduce easily
• In a unit test, mock the underlying interface to the throw the same exception.
– At the very least, we’ll know how to stop this error from crashing the entire app and set up proper logging to identify potential causes
![Page 14: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/14.jpg)
ScenarioProduction issue with unknown cause
[Fact]
public void TestIndex_WebExceptionFromReviewManager()
{
InjectCookieCollectionDependency();
var mock = new Mock<IReviewManager>();
mock.Setup(rm => rm.GetEsReviewsByMovie(
It.IsAny<int>(),
It.IsAny<int>(),
It.IsAny<int>(),
It.IsAny<UserReviewSort>()))
.Throws(new WebException());
IReviewManager reviewManager = mock.Object;
using (var controller = new MovieController(reviewManager) { ControllerContext = new ControllerContext { HttpContext = new MockHttpContext() } })
{
MockHttpContext httpContext = configureContext(UserAgentValue);
controller.ControllerContext.HttpContext = httpContext;
ActionResult result = controller.Index(MovieIdAmericanBeauty);
Assert.IsType(typeof (ViewResult), result);
}
}
![Page 15: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/15.jpg)
ScenarioAnonymous + authenticated users
• Our apps identify a logged in user by the presence of a cookie. We can mock that!– See changes to MovieController with
ICustomerCookieProvider
![Page 16: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/16.jpg)
Strategies for Unit Testing
• New Projects
– TDD allows us to work with QA to identify good test cases before we start writing code
• Legacy Projects
– Don’t test something that’s been working in production for years
– Create unit tests to reproduce your bug. This will allow for immediate ROI on the tests
– Introduce tests for new features
![Page 17: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/17.jpg)
Side Effect (Good)
• Enforces the SOLID principlesSingle Responsibility [link]
If an interface crosses domains, you know to split themMultiple interfaces too many responsibilities for the class
Open/Closed Principle [link]
Your code is inherently open to extension
Liskov Substitution Principle [link]
Your mocks provide are substituted for the concrete implementations without code changes
Interface segregation Principle [link]
Interface contract hides helper methods
Dependency inversion principle [link]
This is what we’re talking about here
![Page 18: Dependency Injection in .NET applications](https://reader031.fdocuments.us/reader031/viewer/2022022419/587fa11b1a28ab825e8b5ebd/html5/thumbnails/18.jpg)
Further Reading
• Martin Fowler (http://martinfowler.com/articles/injection.html)
• AutoFac IoC container (http://autofac.org/)
• AutoFac in action NuGet Gallery – DI by Environment