1. Trang chủ
  2. » Công Nghệ Thông Tin

Mastering ninject for dependency injection

142 305 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 142
Dung lượng 2 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Mastering Ninject for Dependency Injection Learn how Ninject facilitates the implementation of Dependency Injection to solve common design problems of real-life applications Daniel Baha

Trang 2

Mastering Ninject for

Dependency Injection

Learn how Ninject facilitates the implementation

of Dependency Injection to solve common design problems of real-life applications

Daniel Baharestani

BIRMINGHAM - MUMBAI

Trang 3

Mastering Ninject for Dependency Injection

Copyright © 2013 Packt Publishing

All rights reserved No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews

Every effort has been made in the preparation of this book to ensure the accuracy

of the information presented However, the information contained in this book is sold without warranty, either express or implied Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals However, Packt Publishing cannot guarantee the accuracy of this information.First published: September 2013

Cover Image by Daniel Baharestani (baharestani@gmail.com) and

Sheetal Aute (sheetala@packtpub.com)

Trang 5

About the Author

Daniel Baharestani is an experienced IT professional living in Australia He has

a BSc in software engineering and has over 10 years of professional experience in design and development of enterprise applications, mostly focused on Microsoft technologies Daniel is currently working at 3P Learning, which is a global leader in online learning for school-aged students with its flagship platform, Mathletics—used

by more than 3.5 million students in over 10,000 schools worldwide

A book is like a song, which may usually be referred to by its singer's

name, whereas many people are involved in the background to make

it happen

First, I am deeply indebted to my wife, Mona, who has taken all my

responsibilities during this period I understand how hard it was for

her to do everything alone that we used to do together

My special thanks goes to Remo Gloor, the main developers of

Ninject, who kindly accepted the final technical review of this book,

and other technical reviewers, including Daniel Allen, Matt Duffield,

and Ted Winslow for providing valuable feedback

I would also like to thank my manager, Houman, for being helpful

and encouraging, and for understanding how important this book

was to me It would be much difficult to have it done without his

support

Finally, I should acknowledge the whole Packt team, who gave me

this opportunity and guided me through this process, including

but definitely not limited to, Nikhil Chinnari and Yogesh Dalvi, my

commissioning editors, Sneha Modi and Romal Karani, my project

coordinators, and Shrutika Kalbag, the author relationship executive

for opening a door

Trang 6

About the Reviewers

Remo Gloor has worked as a Software Architect at bbv Software Services AG

in Switzerland for many years During this time, he was using Ninject in several projects At the beginning, he was a user of Ninject Later, he contributed with several extensions In 2010, he became manager and the main contributor to Ninject, which was developed originally by Nate Kohari and Ian Davis

Besides his interest in dependency injection and IoC containers, he has also a strong interest in service-oriented and message-driven architectures, as well as event sourcing Because of this, he contributed to the ActiveMq support to NServiceBus

He blogs on http://www.planetgeek.ch/author/remo-gloor/ mainly about Ninject He also answers many Ninject-related questions on stackoverflow:

http://stackoverflow.com/users/448580/remo-gloor

Trang 7

4 development and enterprise architecture design He develops primarily in C#, JavaScript, and Objective-C Because of his heavy focus on enterprise architecture design, Dan has experience in an array of patterns and tools that he has effectively and logically combined together to meet a project's unique needs Dan holds a B.S

in Management Information Systems and an MBA with a concentration in

Information Systems

Dan spends much of his free time working on development-related side contracts and searching for the next great startup idea He aspires to start a consulting firm that will provide capital for the various startup ideas one day For recreation, he enjoys training and competing in various marathons, and aspires to complete a full iron man competition one day

He has formerly worked with Millennium Information Services, Inc as an ASP.NET MVC Web Developer His primary tasks in this role were MVC 4 Razor

development, HTML 5 frontend GUI design, enterprise architecture design,

and WCF, Oracle database, and agile development He has also worked for Arc Worldwide / Leo Burnett as an Associate Software Engineer His primary tasks

in this role were ASP.NET Web Forms development, frontend GUI design, and he also worked on SQL Server database Dan has also worked with American Concrete Pavement Association as a Software Engineer His primary tasks in this role were ASP.NET Web Forms and MVC 4 development, iOS mobile development, and SQL Server database, graphics and media development

For Dan's complete professional history and his online interactive portfolio,

please visit http://www.apexwebz.com

I would like to thank my family for their ongoing support My father inspired me to start working in this field, and now I can't picture

myself doing anything else I would also like to thank my close

friend, past boss, and ongoing mentor, Robert Rodden, for helping

me at every step of the way in my professional career

Trang 8

in IT He enjoys building a rich line of business applications that focus on great user experiences while providing excellent business intelligence, such as dashboards and expert systems His current focus is on client-side MVC architecture and building cross-platform solutions Matt is very active in the community, speaking at user groups and code camps He is an INETA speaker and a Microsoft MVP in client

development He is the co-author of Microsoft Silverlight 5: Building Rich Enterprise Dashboards, Packt Publishing His blog can be found at http://mattduffield.wordpress.com You can follow him on Twitter at @mattduffield Matt is also the leader of the Charlotte ALT.NET user group (http://www.meetup.com/

charlottealtnet/) and Charlotte Game Dev user group (http://www.meetup.com/Charlotte-Game-Dev/) He is also the Vice President of the Charlotte

Enterprise Developers Guild (http://www.developersguild.org/) and also board member of the Carolina Code Camp

Ted Winslow has been one of those programmers who impressed the likes of NASA and Boeing with his skills behind a keyboard ever since his sixth grade Even when he isn't working for one of the big names, he's freelancing for multimillion-dollar shops, and considers writing code a way to relax in his downtime He started writing code while young and did it with little more than a basic starter book and a half-broken computer Against all odds, he has now a lengthy and respected work history with code chops for which large and small companies hunger Nowadays, he's spotted helping people in his free time to make sure the young programmers understand and have a chance to live their dream, even when the odds are stacked against them

I'd like to thank my friends for both the encouragement they've

provided during my career and for putting up with me every day

You all mean a lot to me

Trang 9

At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range

of free newsletters and receive exclusive discounts and offers on Packt books and eBooks.

• Fully searchable across every book published by Packt

• Copy and paste, print and bookmark content

• On demand and accessible via web browser

Free Access for Packt account holders

If you have an account with Packt at www.PacktPub.com, you can use this to access PacktLib today and view nine entirely free books Simply use your login credentials for immediate access.

Trang 10

Table of Contents

Preface 1 Chapter 1: Understanding Dependency Injection 7

What is Dependency Injection? 8

DI or Inversion of Control (IoC) 9

How to use XML configuration 31

Convention over configuration 34

Summary 39

Trang 11

Chapter 3: Meeting Real-world Requirements 41

DI patterns and antipatterns 41

Initializer methods and properties 43

Multi binding and contextual binding 46

Implementing the plugin model 46

Func 70

Summary 71

Chapter 4: Ninject in Action 73

Windows Forms applications 77 WPF and Silverlight applications 81

ASP.NET Web Forms applications 102 Summary 103

Trang 12

Chapter 5: Doing More with Extensions 105

Trang 14

Mastering Ninject for Dependency Injection demonstrates how Ninject facilitates

the implementation of Dependency Injection to solve common design problems

of real-life applications in a simple and easy-to-understand format This book will teach you everything you need in order to implement Dependency Injection using Ninject in a real-life project Not only does it teach the Ninject core framework features which are essential for implementing DI, but it also explores the power

of Ninject's most useful extensions, and demonstrates how to apply them in a real-life application

What this book covers

Chapter 1, Understanding Dependency Injection, introduces Dependency Injection

concepts and describes the advantages of using this technique We will also go through a simple example and implement the principles and patterns related to

DI techniques After understanding what a DI container is, we will discuss why Ninject is a suitable choice

Chapter 2, Getting Started with Ninject, teaches the user how to add Ninject to a

practical project and how to use the basic features of this framework The chapter starts with an example demonstrating how to set up and use Ninject in a Hello World project Then, we will talk about how Ninject resolves dependencies and how

it manages object lifetime We will also cover the code-based configuration using Ninject modules and XML-based configuration The final section of this chapter describes how to configure a large application which includes hundreds of services using Ninject conventions By the end of this chapter, the user will be able to set

up and use the basic features of Ninject

Trang 15

Chapter 3, Meeting Real-world Requirements, introduces more advanced features of

Ninject which are necessary in order to implement DI in real-world situations The chapter starts with an introduction to some patterns and antipatterns related to Ninject We will then go through real examples and see how Ninject can solve such kind of problems By the end of this chapter, the user is expected to know almost all of the significant features of Ninject

Chapter 4, Ninject in Action, shows how to set up different types of applications using

Ninject We will implement a concrete scenario using a variety of application types, including but not limited to, WPF, ASP NET MVC, and WCF, to see how to set up and use Ninject for injecting the dependencies By the end of this chapter, the user should be able to set up and use Ninject for all kinds of described applications

Chapter 5, Doing More with Extensions, will show how Interception is a solution for

cross-cutting concerns, and how to use Mocking Kernel as a test asset While the core library of Ninject is kept clean and simple, Ninject is a highly extensible DI container, and it is possible to extend its power by using extension plugins We will also see how Ninject can be extended

What you need for this book

The examples of the book are written in Microsoft Visual Studio 2012; however, the target framework is set to NET 4.0 so that they can be easily built using

MSBuild and NET Framework 4.0, even if you do not have Visual Studio 2012

In the ASP.NET MVC application, we used MVC 3, and Microsoft SQL Server

Compact 4.0 is used for SQL Data Layer

You need an Internet connection to download required references and online

packages, such as Ninject and its extensions Having NuGet package manager

on your system facilitates installing of referenced packages, but it is not required,

as wherever we need to install such packages, the instruction for manually

downloading and referencing the binaries is also provided

We have also used NUnit for our Unit Tests, which is freely available for download via NuGet or NUnit website

Trang 16

Who this book is for

This book is for all software developers and architects who are willing to create maintainable, loosely coupled, extensible, and testable applications Because Ninject targets the NET platform, this book is not suitable for software developers of other platforms You should be comfortable with object oriented principals, and have

a fair understanding of inheritance and abstraction Being familiar with design patterns and general concept of unit testing is also a great help, but no knowledge

of Dependency Injection is assumed Although Ninject can be used in any NET programming languages, the examples of this book are all in C#, so the reader is assumed to be familiar with this language

Conventions

In this book, you will find a number of styles of text that distinguish between

different kinds of information Here are some examples of these styles, and an explanation of their meaning

Code words in text are shown as follows: "The following example shows how

to use the ILogger interface."

A block of code is set as follows:

[Inject]

public ILogger Logger {get; set;}

public void DoSomething()

{

Logger.Debug("Doing something ");

}

When we wish to draw your attention to a particular part of a code block,

the relevant lines or items are set in bold:

Any command-line input or output is written as follows:

2013-05-23 05:04:40 INFO LogSamples.Consumer - Doing something

Trang 17

New terms and important words are shown in bold Words that you see on the

screen, in menus or dialog boxes for example, appear in the text like this: "The first

one is called when the hyperlink Create New is clicked using HTTP GET method ".

Warnings or important notes appear in a box like this

Tips and tricks appear like this

Reader feedback

Feedback from our readers is always welcome Let us know what you think about this book—what you liked or may have disliked Reader feedback is important for

us to develop titles that you really get the most out of

To send us general feedback, simply send an e-mail to feedback@packtpub.com, and mention the book title through the subject of your message

If there is a topic that you have expertise in and you are interested in either writing

or contributing to a book, see our author guide on www.packtpub.com/authors

Customer support

Now that you are the proud owner of a Packt book, we have a number of things

to help you to get the most from your purchase

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you

Trang 18

Although we have taken every care to ensure the accuracy of our content, mistakes

do happen If you find a mistake in one of our books—maybe a mistake in the text or the code—we would be grateful if you would report this to us By doing so, you can save other readers from frustration and help us improve subsequent versions of this book If you find any errata, please report them by visiting http://www.packtpub.com/support, selecting your book, clicking on the errata submission form link, and

entering the details of your errata Once your errata are verified, your submission will be accepted and the errata will be uploaded to our website, or added to any list

of existing errata, under the Errata section of that title

Piracy

Piracy of copyright material on the Internet is an ongoing problem across all media

At Packt, we take the protection of our copyright and licenses very seriously If you come across any illegal copies of our works, in any form, on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy

Please contact us at copyright@packtpub.com with a link to the suspected

pirated material

We appreciate your help in protecting our authors, and our ability to bring

you valuable content

Questions

You can contact us at questions@packtpub.com if you are having a problem

with any aspect of the book, and we will do our best to address it

Trang 20

Understanding Dependency Injection

"It's more about a way of thinking and designing code than it is about tools

and techniques"

– Mark Seemann

This chapter introduces the Dependency Injection (DI) concepts and describes

the advantages of using this pattern We will also go through a simple example

and implement the principles and patterns related to the DI technique to it After understanding what a DI container is, we will discuss why Ninject is a suitable one

By the end of this chapter, the reader is expected to have a good understanding of

DI and how Ninject can help them as a DI container

The topics covered in this chapter are:

• What is Dependency Injection?

• How can DI help?

• My first DI application

• DI Containers

• Why use Ninject?

Trang 21

What is Dependency Injection?

Dependency Injection is one of the techniques in software engineering which improves the maintainability of a software application by managing the dependent components In order to have a better understanding of this pattern, let's start this section with an example to clarify what is meant by a dependency, and what other elements are involved in this process

Cameron is a skilled carpenter who spends most of his time creating wooden stuffs Today, he is going to make a chair He needs a saw, a hammer, and other tools During the process of creating the chair, he needs to figure out what tool he needs and find it in his toolbox Although what he needs to focus on is how to make

a chair, without thinking of what tools he needs and how to find them, it is not possible to finish the construction of the chair

The following code is the C# representation of Cameron, as a carpenter:

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub

com If you purchased this book elsewhere, you can visit http://

www.packtpub.com/support and register to have the files e-mailed directly to you

Trang 22

This is the C# implementation of Sarah, the surgeon:

class Surgeon

{

private Forceps forceps;

// The forceps object will be injected into the constructor

// method by a third party while the class is being created.

public Surgeon(Forceps forceps)

DI or Inversion of Control (IoC)

Martin Fowler defines Inversion of Control (IoC) as a style of programming in

which the framework takes the control of the flow instead of your code Comparing handling an event to calling a function is a good example to understand IoC When you call the functions of a framework, you are controlling the flow, because you decide in what sequence to call the functions But in case of handling events, you are defining the functions and the framework is calling them, so the control is

inverted to the framework instead of you This example showed you how control can be inverted DI is a specific type of IoC, because instead of your components concern about their dependencies, they are provided with the dependencies by the

framework Indeed, as Mark Seemann states in his book, Dependency Injection in NET, IoC is a broader term which includes, but is not limited to, DI, even though

they are often being used interchangeably IoC is also known as the Hollywood Principle: "Don't call us, we'll call you"

Trang 23

How can DI help?

Every software application is inevitable of change As your code grows and

new requirements arrive, the importance of maintaining your codes becomes

more tangible, and it is not possible for a software application to go on if it is not maintainable One of the design principles that lead to producing a maintainable

code is known as Separation of Concerns (SoC) The SoC is a broad concept and is

not limited to software design; but in the case of composing software components,

we can think of SoC as implementing distinct classes, each of which deals with

a single responsibility In the first example, finding a tool is a different concern from doing the operation itself and separating these two concerns is one of the prerequisites for creating a maintainable code

Separation of concerns, however, doesn't lead to a maintainable code if the sections that deal with concerns are tightly coupled to each other

Although there are different types of forceps that Sarah may need during the

operation, she doesn't need to mention the exact type of forceps which she requires She just states that she needs forceps, and it is on her assistant to determine which forceps satisfies her need the best If the exact type that Sarah needs is temporarily not available, the assistant has the freedom to provide her with another suitable type If the hospital has bought a new type of forceps that the assistant thinks is more suitable, he or she can easily switch to the new one because he or she knows that Sarah doesn't care about the type of forceps as long as it is suitable In other words, Sarah is not tightly coupled to a specific type of forceps

The key principle leading to loose coupling is the following, from the Gang of Four

(Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software):

"Program to an "interface", not an "implementation"."

When we address our dependencies as abstract elements (an interface or abstract class), rather than concrete classes, we will be able to easily replace the concrete classes without affecting the consumer component:

class Surgeon

{

private IForceps forceps;

public Surgeon(IForceps forceps)

{

this.forceps = forceps;

}

Trang 24

public void Operate()

var forceps = assistant.Get<IForceps>();

var surgeon = new Surgeon (forceps);

Because the Surgeon class is programmed to the IForceps interface rather than a certain type of forceps implementation, we can freely instantiate it with any type of forceps that the assistant object decides to provide

As the previous example shows, loose coupling (surgeon is not dependent on a certain type of forceps) is a result of programming to interface (surgeon depends on IForceps) and separation of concerns, (choosing forceps is the assistant's concern, while the surgeon has other concerns) which increases the code maintainability.Now that we know loose coupling increases the flexibility and gives freedom of replacing the dependencies easily; let's see what else we get out of this freedom other than maintainability One of the advantages of being able to replace the

concrete classes is testability As long as the components are loosely coupled to their

dependencies, we can replace the actual dependencies with Test Doubles such as

mock objects Test Doubles are simplified version of the real objects that look and behave like them and facilitate testing The following example shows how to unit test the Surgeon class using a mock forceps as a Test Double:

[Test]

public void CallingOperateCallsGrabOnForceps()

{

var forcepsMock = new Mock<IForceps>();

var surgeon = new Surgeon(forcepsMock.Object);

surgeon.Operate();

forcepsMock.Verify(f => f.Grab());

}

Trang 25

In this unit test, an instance of the Surgeon class is being created as a System Under

Test (SUT), and the mock object is injected into its constructor After calling the

Operate method on the surgeon object, we ask our mock framework to verify whether the Grab operation is called on the mock forceps object as expected

Maintainability and testability are two advantages of loose coupling, which is in turn

a product of Dependency Injection On the other hand, the way an Injector creates the instances of concrete types, can introduce the third benefit of DI, which is the late binding An Injector is given a type and is expected to return an object instance of that type It often uses reflection in order to activate objects So, the decision of which type to activate can be delayed to the runtime Late binding gives us the flexibility of replacing the dependencies without recompiling the application Another benefit of

DI is extensibility Because classes depend on abstractions, we can easily extend their functionality by substituting the concrete dependencies

My First DI Application

We start our example with a service class in which the concerns are not separated Then we will improve maintainability step-by-step, by first separating concerns and then programming to interface in order to make our modules loosely coupled At the final point, we will have our first DI application The source code

for all the examples of this book is available for download on the publisher's website.The main responsibility of this service is to send an e-mail using the information provided In order to make the example simple and clear, client initialization

var client = new SmtpClient();

// Setup client with smtp server address and port here

Trang 26

Console.WriteLine("Creating mail message ");

var mail = new MailMessage();

mail.To.Add(address);

mail.Subject = subject;

mail.Body = body;

var client = new SmtpClient();

// Setup client with smtp server address and port here

we have to change the MailService class So, let's re-factor this class and separate the concern of logging from sending a mail prior to adding the time functionality:class MailService

logger.Log("Creating mail message ");

var mail = new MailMessage();

mail.To.Add(address);

mail.Subject = subject;

mail.Body = body;

var client = new SmtpClient();

// Setup client with smtp server address and port here

Trang 27

The ConsoleLogger class is only responsible for the logging mechanism, and this concern is removed from MailService Now, it is possible to modify the logging mechanism without affecting MailService:

Now, we need to write our logs in Windows Event Log rather than showing them

in console Looks like we need an EventLogger class as well:

Trang 28

public void Log(string message)

public MailService(ILogger logger)

internal class Program

{

private static void Main(string[] args)

{

var mailService = new MailService(new EventLogger());

mailService.SendMail("someone@somewhere.com", "My first DI

App", "Hello World!");

}

}

The main method of this application is where we decide what concrete objects to inject in our dependent classes This (preferably) unique location in the application where modules are composed together is named Composition Root by Mark

Seemann For more information on DI, Dependency Injection in NET, by Mark Seemann

is recommended

Trang 29

DI Containers

A DI container is an injector object that injects the dependencies into a dependent object As we have seen in the previous example, we don't necessarily need a DI container in order to implement Dependency Injection However, in more complex scenarios, a DI container can save a lot of time and effort by automating most of the tasks that we had to do manually In real world applications, a single dependant class can have many dependencies, each of which have their own dependencies that forms a large graph of dependencies A DI container should resolve the

dependencies, and this is where the decision of selecting a concrete class for the given abstraction should be made This decision is made by a mapping table, which is either based on a configuration file or is programmatically defined by the developer We can see an example for both here:

<bind service="ILogger" to="ConsoleLogger" />

This one is an example of code-based configuration:

Bind<ILogger>().To<ConsoleLogger>();

We can also define conditional rules instead of just mapping a service to a concrete

type We will discuss this feature in detail in Chapter 2, Getting Started with Ninject.

A container has the responsibility of dealing with the lifetime of the created objects

It should know how long an object should be kept alive, when to dispose of it,

in what condition to return the existing instance, and in what condition to create

a new one

DI Containers are also known as IoC Containers

There are other DI Container besides Ninject You can find a list of

them in Scott Hanselman's blog (http://www.hanselman.com/blog/

ListOfNETDependencyInjectionContainersIOC.aspx) Unity, Castle Windsor, StructureMap, Spring.NET, and Autofac are a few of them:

Trang 30

Well documented and used by many.

Written by Jeremy D

Miller

Written

by Mark Pollack

Written by Nicholas Blumhardt and Rinat Abdullin

Why use Ninject?

Ninject is a lightweight Dependency Injection framework for NET applications

It helps you split your application into a collection of loosely-coupled,

highly-cohesive pieces, and then glues them back together in a flexible manner By using Ninject to support your software's architecture, your code will become easier to write, reuse, test, and modify Instead of relying on reflection for invocation, Ninject

takes advantage of lightweight code generation in the CLR (Common Language

Runtime) This can result in a dramatic (8-50x) improvement in performance in

many situations Ninject includes many advanced features For example, Ninject was the first dependency injector to support contextual binding, in which a different concrete implementation of a service may be injected, depending on the context in which it is requested Ninject supports most major facilities offered by the competing

frameworks (although, many such elements live in extensions: plugin modules that

layer on facilities on top of the core) You can have a look at the Ninject official wiki

at https://github.com/ninject/ninject/wiki for a more detailed list of Ninject features which makes it one of the top DI containers

Summary

Dependency Injection is a technique to help us produce loosely coupled code by moving the concern of creating the dependencies to another object known as a DI container In other words, instead of a dependent object to decide what concrete class

it needs, it just states the needs as an abstraction, and the injector provides it with the most suitable concrete class that satisfies the needs Loose coupling is one of the main advantages of DI that leads to extensibility, maintainability, and testability Late binding is another benefit of DI and dynamic loading of plugins is an example of this feature There are DI containers other than Ninject, each of which has their own advantages and disadvantages

Trang 32

Getting Started with Ninject

This chapter teaches the user how to add Ninject to a practical project and use the basic features of this framework The chapter starts with an example demonstrating how to setup and use Ninject in a Hello World project Then, we will talk about how Ninject resolves dependencies and how it manages object lifetime Final sections

of this chapter will cover code-based configuration using Ninject modules and XML-based configuration using an XML file By the end of this chapter, the user will be able to setup and use basic features of Ninject

The topics covered in this chapter are:

Trang 33

1 The first step to setup Ninject is to download Ninject library You can do it either using NuGet or by downloading the binary file If you have NuGet package manager, create a new Console Application project in Visual Studio, and then simply search for Ninject in NuGet UI to install the package, as the following figure illustrates Alternatively, you can type install-package Ninject, and then press enter in the Packet Manager Console located at

View | Other Windows menu Once the installation of Ninject package is

finished, jump to step 5 If you don't have NuGet package manager, go to the download page of Ninject official website (http://www.ninject.org/download.html) and download the most recent version for your desired framework Considering Ninject is an open source project, you can even download the source codes from GitHub via the link provided on the

download page

2 In Windows Vista and other newer versions of Windows, you need to unblock the downloaded archive prior to uncompressing it, in order

to prevent further security issues at runtime Simply right-click on the

downloaded file, open Properties, and from the General tab, click on the

Unblock button Then, unzip the archive to your libraries directory (for

example, D:\Libraries\Ninject)

3 Open Visual Studio and create a new Console Application project

4 Add a reference to Ninject.dll in your library directory

5 Add a new class to your project and call it SalutationService:

6 Add using Ninject to the using section of Program.cs

7 Add the following lines to your Main method:

using (var kernel = new Ninject.StandardKernel())

{

var service = kernel.Get<SalutationService>();

service.SayHello();

}

Trang 34

8 Run the application.

That is how Ninject works in the simplest way We didn't even need to add

any configuration or annotation Although we didn't have anything to inject

in the previous example, Ninject did its main job, which was resolving a type

(SalutationService)

Let's have a look at the Main method to see what was happening there In the first line, we created a kernel object by instantiating StandardKernel Kernel is always the start point of creating our dependency graph In this simple example, the graph only consists of one type, which is SalutationService As we see, we didn't call the constructor of SalutationService in neither of the Main method lines Instead,

we asked our container (kernel) to do it for us We gave our required type to the Get method, and it returned an instance of the given type In other words, the Getmethod was provided with the root type (SalutationService) of our dependency graph and returned the graph object

Now that we know how to setup Ninject, let's move ahead to a more complex

example to see how Ninject helps us to implement DI better

Trang 35

It's all about Binding

In Chapter 1, Understanding Dependency Injection, we implemented DI manually in the

MailService class You remember that we ignored the configuration of SmtpClient

to simplify the project Now, we are going to add the configuration of SmtpClientand implement DI using Ninject

Let's start by creating the MailConfig class:

Trang 36

Now, we can update the MailService class and incorporate MailServiceConfig:class MailService

{

private ILogger logger;

private SmtpClient client;

private string sender;

Trang 37

We have added a new method called InitializeClient, which instantiates and initializes the client field using the given MailServerConfig object.

The constructor has been added another parameter, which accepts an object of MailServerConfig, which contains some settings obtained from the application configuration file

The following figure shows the dependency graph of this application:

Now, let's see how Ninject is going to resolve the dependencies and create the graph object Considering the last example, we need a kernel object and give it the starting node of our graph, so that it returns the entire graph as the following code shows:var kernel = new StandardKernel();

var mailService = kernel.Get<MailService>();

Ninject starts by resolving the MailService type It finds the type and realizes that

in order to instantiate it, first it should create an instance of MailServerConfig and ILogger That is because Ninject automatically creates arguments that should be passed to the constructor of the type being instantiated It injects these arguments

to the constructor parameters without us having to instruct it to do so Creating an instance of MailServerConfig is as easy as calling its only constructor, but what about ILogger? ILogger is an interface, and it is not possible to create an instance

of an interface itself Also, it may have multiple implementations So, how is Ninject supposed to know which implementation of ILogger to use?

Ninject uses its Binding system to decide what implementation to use for a given type A binding is an instruction which maps one type (usually an abstract type or

an interface) to a concrete type that matches such a given type This process is also

called Service Registration.

Trang 38

The following code instructs Ninject how to resolve ILogger:

kernel.Bind<ILogger>().To<ConsoleLogger>();

It means that Ninject should always use the ConsoleLogger type as an

implementation type for the ILogger type

The final Main method's body looks like this:

using (var kernel = new StandardKernel())

{

kernel.Bind<ILogger>().To<ConsoleLogger>();

var mailService = kernel.Get<MailService>();

mailService.SendMail("someone@domain.com", "Hi", null);

One of the responsibilities of a DI container is to manage the lifetime of objects that

it creates It should decide when to create a new instance of the given type and when

to use an existing instance It should also take care of disposing of objects when they are not used anymore Ninject has a strong support for managing Object Lifetime in different situations Whenever we define a binding, we can declare the scope of the object instance being created Within that scope, the object instance will be reused and exist exactly once for each binding Note that an object is not allowed to have a dependency on an object with shorter lifetime

Transient scope

In Transient scope, the object lifetime is not managed by Ninject Whenever we request an instance of a type, a new one will be created Ninject doesn't take care of keeping the created instance or disposing of it in this scope This is the default object scope in Ninject If no scope is explicitly specified, they are transient-scoped In the previous code, both ConsoleLogger and MailService were treated in the Transient scope because the object scope was not specified

Trang 39

Singleton scope

In the previous example, the ILogger interface is bound to the ConsoleLogger class, which means whenever Ninject encounters ILogger, it should create a new instance

of ConsoleLogger But we don't really need multiple instances of ConsoleLogger

in all of the classes that need to log to console Looks like it is a good idea to make ConsoleLogger singleton There are two approaches to achieve this The first one

is using one of the Singleton patterns:

kernel.Bind<ILogger>().ToConstant(ConsoleLogger.Instance);

However, if we make a singleton type like this, we will draw some limitations to our class For example, we won't be able to unit test, it because it doesn't have a default constructor

Using lifetime management of Ninject, we will be able to have singleton objects without having to make their type singleton All we need to do is to instruct Ninject

to treat the given type as singleton:

kernel.Bind<MailServerConfig>().ToSelf().InSingletonScope();

Trang 40

Thread scope

If we define a binding in Thread scope, only one instance of the given type will

be created per thread The object lifetime is as long as the lifetime of the underlying Thread object

The following test asserts equality of instances created by Ninject in the same thread:[Test]

public void ReturnsTheSameInstancesInOneThread()

{

using (var kernel = new StandardKernel())

{

kernel.Bind<object>().ToSelf().InThreadScope();

var instance1 = kernel.Get<object>();

var instance2 = kernel.Get<object>();

The test succeeded

The following test demonstrates inequality of the instances created from the

same type but in different threads:

Ngày đăng: 13/03/2019, 10:46

TỪ KHÓA LIÊN QUAN