AngularJS. Внедрение зависимости (Dependency injection)


Содержание материала:

Stepan Suvorov Blog

Release 2.0

Модули AngularJS и внедрение зависимостей

Как извесно Dependency Injection – это один из основных концептов архитектуры AngularJS. Разберем несколько примеров использования сервисов в модулях.

За основу данного поста я взял вот эту статью, которую перевел и немного поправил.

Представим что у нас в модуле foo есть примитивный сервис simpleService

Теперь представим, что мы хотим вручную получить экземпляр этого сервиса (что в практике скорее всего делать не прийдется) и использовать. Чтобы сделать это, мы создадим новый injector и поручим ему магию создания сервиса для нас:

Итак, это именно оно… самый простой случай. Но что если у нас 2 модуля с сервисами, которые имеют одинаковые имена? Что тогда? Тут уже становится интересно, давайте рассмотрим еще пример:

Это похоже на то, что мы ожидали увидеть: каждый инжектор относится только к одному модулю и поэтому сервисы изолированы . Но ведь мы можем создать инжектор, который будет относиться более чем одному модулю. Что будет тогда?

Видите что произошло? Модуль, который регистрируется последним, перезаписывает другие одноименные с ним модули.

Но что если модули имеют зависимости? Что это меняет?

И тут тоже все решает порядок, но в этом случае нужно помнить о том, что модули-зависимости основного модуля будут проинициализированы первыми, т.е. для модуля bar сначала будет проинициализирован модуль-зависимость foo.

Представим, что мы тестируем приложение и хотим заменить $httpBackend сервис на наш кастомный вариант или заменить его на mock с заранее известным поведением. Это очень просто сделать в рамках архитектуры Ангулара. Все что необходимо – это создать модуль, который будет иметь зависимость от ng module и переопределить необходимый сервис(т.е. объявить в нашем модуле сервис с таким же именем).

Замена сервиса – это хорошо, но что особенно здорово в Ангулар – возможность получить сервис сразу после его создания. Это может быть достигнуто путем использования декоратора (decorator):

(С кодом можно поиграться тут)

Не вдаваясь в подробности можно сказать что у нас есть возможность получить simpleService из foo и преобразовать его. Более подробно можно почитать в документации о методах config и decorator.

AngularJS — Dependency Injection

Dependency Injection is a software design in which components are given their dependencies instead of hard coding them within the component. It relieves a component from locating the dependency and makes dependencies configurable. It also helps in making components reusable, maintainable and testable.

AngularJS provides a supreme Dependency Injection mechanism. It provides following core components which can be injected into each other as dependencies.

Value

Value is a simple JavaScript object, which is required to pass values to the controller during config phase (config phase is when AngularJS bootstraps itself).

Factory

Factory is a function which is used to return value. It creates a value on demand whenever a service or a controller requires it. It generally uses a factory function to calculate and return the value.

Service

Service is a singleton JavaScript object containing a set of functions to perform certain tasks. Service is defined using service() function and it is then injected into the controllers.

Provider

Provider is used by AngularJS internally to create services, factory, etc. during the config phase. The following script can be used to create MathService that we created earlier. Provider is a special factory method with get() method which is used to return the value/service/factory.

Constant

Constants are used to pass values at the config phase considering the fact that value cannot be used during the config phase.

Example

The following example shows the use of all the above-mentioned directives −

Understanding Dependency Injection

Dependency injection in AngularJS is supremely useful, and the key to making easily testable components. This article explains how Angular’s dependency injection system works.

The $provide service is responsible for telling Angular how to create new injectable things; these things are called services. Services are defined by things called providers, which is what you’re creating when you use $provide . Defining a provider is done via the provider method on the $provide service, and you can get hold of the $provide service by asking for it to be injected into an application’s config function. An example might be something like this:

Here we’ve defined a new provider for a service called greeting ; we can inject a variable named greeting into any injectable function (like controllers, more on that later) and Angular will call the provider’s $get function in order to return a new instance of the service. In this case, the thing that will be injected is a function that takes a name parameter and alert s a message based on the name. We might use it like this:

Now here’s the trick. factory , service , and value are all just shortcuts to define various parts of a provider—that is, they provide a means of defining a provider without having to type all that stuff out. For example, you could write that exact same provider just like this:

It’s important to understand, so I’ll rephrase: under the hood, AngularJS is calling the exact same code that we wrote above (the $provide.provider version) for us. There is literally, 100% no difference in the two versions. value works just the same way—if whatever we would return from our $get function (aka our factory function) is always exactly the same, we can write even less code using value . For example, since we always return the same function for our greeting service, we can use value to define it, too:

Again, this is 100% identical to the other two methods we’ve used to define this function—it’s just a way to save some typing.

Now you probably noticed this annoying myMod.config(function($provide) < . >) thing I’ve been using. Since defining new providers (via any of the given methods above) is so common, AngularJS exposes the $provide methods directly on the module object, to save even more typing:

These all do the same thing as the more verbose app.config(. ) versions we used previously.

The one injectable I’ve skipped so far is constant . For now, it’s easy enough to say that it works just like value . We’ll see there’s one difference later.

To review, all these pieces of code are doing the exact same thing:

The injector is responsible for actually creating instances of our services using the code we provided via $provide (no pun intended). Any time you write a function that takes injected arguments, you’re seeing the injector at work. Each AngularJS application has a single $injector that gets created when the application first starts; you can get a hold of it by injecting $injector into any injectable function (yes, $injector knows how to inject itself!)

Once you have $injector , you can get an instance of a defined service by calling get on it with the name of the service. For example,

The injector is also responsible for injecting services into functions; for example, you can magically inject services into any function you have using the injector’s invoke method;

It’s worth noting that the injector will only create an instance of a service once. It then caches whatever the provider returns by the service’s name; the next time you ask for the service, you’ll actually get the exact same object.

So, it stands to reason that you can inject services into any function that is called with $injector.invoke . This includes

  • controller definition functions
  • directive definition functions
  • filter definition functions
  • the $get methods of providers (aka the factory definition functions)

Since constant s and value s always return a static value, they are not invoked via the injector, and thus you cannot inject them with anything.

You may be wondering why anyone would bother to set up a full-fledged provider with the provide method if factory , value , etc. are so much easier. The answer is that providers allow a lot of configuration. We’ve already mentioned that when you create a service via the provider (or any of the shortcuts Angular gives you), you create a new provider that defines how that service is constructed. What I didn’t mention is that these providers can be injected into config sections of your application so you can interact with them!

First, Angular runs your application in two phases—the config and run phases. The config phase, as we’ve seen, is where you can set up any providers as necessary. This is also where directives, controllers, filters, and the like get set up. The run phase, as you might guess, is where Angular actually compiles your DOM and starts up your app.

You can add additional code to be run in these phases with the myMod.config and myMod.run functions—each take a function to run during that specific phase. As we saw in the first section, these functions are injectable—we injected the built-in $provide service in our very first code sample. However, what’s worth noting is that during the config phase, only providers can be injected (with the exception of the services in the AUTO module— $provide and $injector ).

For example, the following is not allowed:

What you do have access to are any providers for services you’ve made:

There is one important exception: constant s, since they cannot be changed, are allowed to be injected inside config blocks (this is how they differ from value s). They are accessed by their name alone (no Provider suffix necessary).

Whenever you defined a provider for a service, that provider gets named serviceProvider , where service is the name of the service. Now we can use the power of providers to do some more complicated stuff!

Now we have a function on our provider called setText that we can use to customize our alert ; we can get access to this provider in a config block to call this method and customize the service. When we finally run our app, we can grab the greeting service, and try it out to see that our customization took effect.

Since this is a more complex example, here’s a working demonstration: http://jsfiddle.net/BinaryMuse/9GjYg/

You can inject things into controllers, but you can’t inject controllers into things. That’s because controllers aren’t created via the provider. Instead, there is a built-in Angular service called $controller that is responsible for setting up your controllers. When you call myMod.controller(. ) , you’re actually accessing this service’s provider, just like in the last section.

For example, when you define a controller like this:

What you’re actually doing is this:

Later, when Angular needs to create an instance of your controller, it uses the $controller service (which in turn uses the $injector to invoke your controller function so it gets its dependencies injected too).

Filters and Directives


filter and directive work exactly the same way as controller ; filter uses a service called $filter and its provider $filterProvider , while directive uses a service called $compile and its provider $compileProvider . Some links:

As per the other examples, myMod.filter and myMod.directive are shortcuts to configuring these services.

So, to summarize, any function that gets called with $injector.invoke can be injected into. This includes, but is not limited to:

  • controller
  • directive
  • factory
  • filter
  • provider $get (when defining provider as an object)
  • provider function (when defining provider as a constructor function)
  • service

The provider creates new services that can be injected into things. This includes:

That said, built-in services like $controller and $filter can be injected, and you can use those services to get hold of the new filters and controllers you defined with those methods (even though the things you defined aren’t, by themselves, able to be injected into things).

Other than that, any injector-invoked function can be injected with any provider-provided service—there is no restriction (other than the config and run differences listed herein).

AngularJS — dependency injection

I would like to know if there is a difference between the two next lines and why to use one of those (the two work as expected)

I took it from the official AngularJS tutorial and I know there is an explanation about this modification but I don’t understand it. http://docs.angularjs.org/tutorial/step_05

Топ-пост этого месяца:  Как скрыть пост

Thanks in advance!

3 Answers 3

If you minify your first line you get:

The dependency injection won’t work then, because Angular has no idea what e and t are. Compare that to minifying the second version:

The function parameters are still renamed, but $scope and $http are given in the array so the injection can go ahead as expected.

There is no difference in terms of functionality. The first one may get messed up if your code is minified because angular resolves from the argument names. The latter has some kind of protection against minification because you are already passing dependencies in array.

AngularJS invokes certain functions (like service factories and controllers) via the injector. You need to annotate these functions so that the injector knows what services to inject into the function. There are three ways of annotating your code with service name information:

  • Using the inline array annotation (preferred)
  • Using the $inject property annotation
  • Implicitly from the function parameter names (has caveats)

Not the answer you’re looking for? Browse other questions tagged angularjs dependency-injection or ask your own question.

Linked

Related

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

site design / logo © 2020 Stack Exchange Inc; user contributions licensed under cc by-sa 4.0 with attribution required. rev 2020.11.7.35374

Dependency Injection in AngularJS with Example

What is Dependency Injection in AngularJS?

Dependency Injection is a software design pattern that implements inversion of control for resolving dependencies.

Inversion of Control: It means that objects do not create other objects on which they rely to do their work. Instead, they get these objects from an outside source. This forms the basis of dependency injection wherein if one object is dependent on another; the primary object does not take the responsibility of creating the dependent object and then use its methods. Instead, an external source (which in AngularJS, is the AngularJS framework itself) creates the dependent object and gives it to the source object for further usage.

So let’s first understand what a dependency is.

The above diagram shows a simple example of an everyday ritual in database programming.

  • The ‘Model’ box depicts the «Model class» which is normally created to interact with the database. So now the database is a dependency for the «Model class» to function.
  • By dependency injection, we create a service to grab all the information from the database and get into the model class.

In the remainder of this tutorial, we will look more at dependency injection and how this is accomplished in AngularJS.

Which Component can be Injected as a Dependency In AngularJS

In Angular.JS, dependencies are injected by using an «injectable factory method» or «constructor function».

These components can be injected with «service» and «value» components as dependencies. We have seen this in an earlier topic with the $http service.

We’ve already seen that the $http service can be used within AngularJS to get data from a MySQL or MS SQL Server database via a PHP web application.

The $http service is normally defined from within the controller in the following manner.

Now when the $http service is defined in the controller as shown above. It means that the controller now has a dependency on the $http service.

So when the above code gets executed, AngularJS will perform the following steps;

  1. Check to see if the «$http service» has been instantiated. Since our «controller» now depends on the «$http service», an object of this service needs to be made available to our controller.
  2. If AngularJS finds out that the $http service is not instantiated, AngularJS uses the ‘factory’ function to construct an $http object.
  3. The injector within Angular.JS then provides an instance of the $http service to our controller for further processing.

Now that the dependency is injected into our controller, we can now invoke the necessary functions within the $http service for further processing.

Example of Dependency Injection

Dependency injection can be implemented in 2 ways

  1. One is through the «Value Component»
  2. Another is through a «Service»

Let’s look at the implementation of both ways in more detail.

1) Value component

This concept is based on the fact of creating a simple JavaScript object and pass it to the controller for further processing.

This is implemented using the below two steps

Step 1) Create a JavaScript object by using the value component and attach it to your main AngularJS.JS module.

The value component takes on two parameters; one is the key, and the other is the value of the javascript object which is created.

Step 2) Access the JavaScript object from the Angular.JS controller

In the above code example, the below main steps are being carried out

The value function of the Angular.JS JS module is being used to create a key-value pair called «TutorialID» and the value of «5».

The TutorialID variable now becomes accessible to the controller as a function parameter.

The value of TutorialID which is 5, is now being assigned to another variable called ID in the $scope object. This is being done so that value of 5 can be passed from the controller to the view.

The ID parameter is being displayed in the view as an expression. So the output of ‘5’ will be displayed on the page.

When the above code is executed, the output will be shown as below

2) Service

Service is defined as a singleton JavaScript object consisting of a set of functions that you want to expose and inject in your controller.

For example, the «$http» is a service in Angular.JS which when injected in your controllers provides the necessary functions of


( get() , query() , save() , remove(), delete() ).

These functions can then be invoked from your controller accordingly.

Let’s look at a simple example of how you can create your own service. We are going to create a simple addition service which adds two numbers.

In the above example, the following steps are carried out

Here we are creating a new service called ‘AdditionService’ using the service parameter of our main AngularJS JS module.

Here we are creating a new function called Addition within our service. This means that when AngularJS instantiates our AdditionService inside of our controller, we would then be able to access the ‘Addition’ function. In this function definition, we are saying that this function accepts two parameters, a and b.

Here we are defining the body of our Addition function which simply adds the parameters and returns the added value.

This is the main step which involves dependency injection. In our controller definition, we are now referencing our ‘AdditionService’ service. When AngularJS see’s this, it will instantiate an object of type ‘AdditionService.’

We are now accessing the function ‘Addition’ which is defined in our service and assigning it to the $scope object of the controller.

So this is a simple example of how we can define our service and inject the functionality of that service inside of our controller.

Summary:

  • Dependency Injection as the name implies is the process of injecting dependent functionality into modules at run time.
  • Using dependency injection helps in having a more re-usable code. If you had common functionality that is used across multiple application modules, the best way is to define a central service with that functionality and then inject that service as a dependency in your application modules.
  • The value object of AngularJS can be used to inject simple JavaScript objects in your controller.
  • The service module can be used to define your custom services which can be re-used across multiple AngularJS modules.

AngularJS Dependency Injection Components – Annotation & Introspection

by DataFlair Team · March 6, 2020

Since, we studied about AngularJS API. Here, we will talk about AngularJS Dependency Injection. Moreover, we will learn components, annotations, introspection, and example of dependency injection in AngularJS.

What is AngularJS Dependency Injection?

AngularJS Dependency injection defines, how the various components of the software are dependent on each other. Instead of hard-coding a component within another component, a component is given their own dependencies using dependency injection.

Why Dependency Injection?

  • AngularJS Dependency injections make an application modularize.
  • AngularJS DI makes easier to reuse components of an application.
  • It makes easier to test components of an application.
  • It makes easier to configure components of an application.

Components of Dependency Injection in Angular JS

In the form of dependencies, we can inject this set of AngularJS Dependency Injection components. AngularJS provides a supreme dependency mechanism.

List of some core components which can be injected as a dependency in one another:

1. Value

Value is an object. It can be a number, string or javascript object. It is used to pass the value to controller, service or factories in config or run phase.

value() function is used on module to define values. It consists of two parameters, the first parameter is the name of the value and the second parameter is assigned value. Now, these values can be referenced by their names in factories, services, and controllers.

Output:

Tutorial Id is:

2. Service

It is like a singleton javascript object. It consists of a set of functions to execute certain tasks. Service() function is used on a module to create services. After creation, it is injected into the controller.

Output:
Result: 11

Note – Config phase is the phase in which angular JS bootstraps itself.

3. Constant

It is used to pass value at config phase irrespective of the fact that value cannot be passed during the config phase.

4. Provider

In the config phase, factory and service are created by using a provider.

5. Factory

A factory is a function that returns value on demand. It returns value on the basis of the requirement made by service and controller. It uses factory function to process the value and return the output.

AngularJS Dependency Injection example-

Output:

Enter a Number:10

AngularJS Dependency Annotation

Some functions like controller, service, and factories are invoked through the injector in AngularJS. Therefore, it is required to annotate these functions, so that injector will be well aware of which function is to be injected.

Angular provides three ways of annotating code. It is provided with a service name.

1. Inline Array Annotation

To annotate components in angular, inline array annotation is mostly used.

An example that illustrates registering a controller to a module.

In the above example, an array is used. The elements of an array are the name of dependencies and are of string type followed by a function.

2. $inject Property Annotation

It is an array of dependency names that are being injected in the function. You can use the $inject property only when, it is allowed to rename the function parameter in your code and still to inject the right services.

Since it is an array of dependency names, therefore, synchronization is necessary between the array and the parameters in the function declaration.

3. Implicit Annotation

It is the easiest way. But if you are minifying code then you cannot use implicit annotation. Because the name of your service will get change as it will get rename then this service will not be available to that function. The parameters passed inside a function are treated as the name of services.

In the above code, $scope and MyService are the names of services, which pass as a parameter inside a function(). Inside a controller, these services already injects. Here, we don’t require any synchronization of anything with the parameter pass inside the function because there is no array of names. Therefore, we can rearrange dependencies in the function declaration.

Strict Dependency Injection in AngularJS

We can opt for strict dependency injection in AngularJS by using ng-strict-di directive. It will apply on the same element as ng-app. When you use strict mode, it will throw an error. When we use service by an implicit annotation.

Output:

In the below example we are using implicit dependency injection in a service name as willBreak. So when the service named as willBreak is instantiated, an error is thrown by angular JS because of its strict mode.

By providing strictDi: true in the optional config argument, we can use strict dependency injection in manual bootstrapping.

Introspection

Generally when you declare a function with parameters, it is the responsibility of users to pass the parameter inside the function in appropriate order.

For example : Suppose you are declaring a function details with two parameter id and name.

Then the function is called by passing values in it but in the same order as it is passed in function declaration. It means for the function details you have to first pass id then name while calling that function.

Similarly in angular JS when you create components like controller, services you need to declare a function in it. This function contains the elements of angular JS.


Here the component controller receives two parameter name of controller and array of elements. ‘DemoController’ is the name of controller. $scope and $log are the two elements of an array follow by an anonymous function. Function contains the same elements of array passed inside it and also in the same order.

Топ-пост этого месяца:  Как прототипировать Vue js компоненты использование фреймворка Protovue, примеры кода

AngularJS Dependency Injection Example

But in the above example there is a duplication. First you declare a string then you are passing the same string through function. Although we don’t need to do this but if we don’t do so at the time of minify our code may break.

Many times we had seen angular code like this:

In this code, there is no duplication. We can pass the same string through function, when there is no array of strings can pass.

This is because of introspection, but the only problem is at the time of minifying of javascript code, the scripts parameter name will also get shorten.

And at the time of function call, angular cannot be able to recognize which function to call. This problem does not arise in case of duplication.

Conclusion

AngularJS Dependency injection is the process of injecting dependent functionality at run time into modules. It helps in achieving reusability of code. Suppose you have a functionality that can use at multiple places in a single application so better to define a central service for it and then inject into different modules of an application as a dependency.

Hope, you liked this AngularJS Dependency Injection. In our next tutorial, we will discuss events in AngularJS.

We would love to hear you in the comment section!

Dependency Injection на пальцах?

Ну вот нужно тебе использовать какой то функционал. Реализованный в виде класса, функции и т.п.

Если ты будешь явно вызывать эту функцию, обращаться к классу — это явная зависимость.

Но если тебе передать эту функцию или класс как переменную — это внедренная зависимость.

То есть сегодня одну функцию/класс передали, завтра другую (лишь бы они были совместимы по сигнатуре) — твоя программа даже разницы не заметит.

DI позволяет создать единый «реестр», где вы можете указать какие классы будут синглтонами (и.е. один и тот же экземпляр каждый раз), а какие создаваться фабриками (и.е. каждый раз создавать новый экземпляр). Более того, в тех же классах вы можете «подтягивать» нужные вам зависимости (экземпляры классов) просто указывая нужный класс, а DI берет на себя работу того, как именно он получит эти экземпляры. Он упрощает вам жизнь, ибо вы можете один раз указать ЧТО вам нужно вместо того, что бы получать это самому. Более того, в любой момент вы можете подменить одну зависимость на другую. Например, есть у вас интерфейс и два класса его реализующие. Во всем приложении вы общаетесь только с интерфейсом, а в DI вы указываете какой из них будет использоватся, причем это можно менять «на лету».

Кроме того вы можете строить бесконечные дерева зависимостей классов и даже делать два класса зависимыми один от другого, указывая правила их резолвинга в DI.

Архитектурные вопросы сложны по определению. Чтобы их понимать, нужно иметь достаточную базу знаний и опыта программирования. В идеале, чтобы понять паттерн, нужно столкнутся с проблемой, для решения которой он был придуман. Если база знаний и опыта уже есть, а понимания всё ещё нет, то прочитайте учебник, вроде «Чистой архитектуры» Мартина.

А «на пальцах» вам сейчас дадут множество объяснений, большинство которых будут неправильными и запутают ещё больше.

Understanding Dependency Injection

Dependency injection in AngularJS is supremely useful, and the key to making easily testable components. This article explains how Angular’s dependency injection system works.

The $provide service is responsible for telling Angular how to create new injectable things; these things are called services. Services are defined by things called providers, which is what you’re creating when you use $provide . Defining a provider is done via the provider method on the $provide service, and you can get hold of the $provide service by asking for it to be injected into an application’s config function. An example might be something like this:

Here we’ve defined a new provider for a service called greeting ; we can inject a variable named greeting into any injectable function (like controllers, more on that later) and Angular will call the provider’s $get function in order to return a new instance of the service. In this case, the thing that will be injected is a function that takes a name parameter and alert s a message based on the name. We might use it like this:

Now here’s the trick. factory , service , and value are all just shortcuts to define various parts of a provider—that is, they provide a means of defining a provider without having to type all that stuff out. For example, you could write that exact same provider just like this:

It’s important to understand, so I’ll rephrase: under the hood, AngularJS is calling the exact same code that we wrote above (the $provide.provider version) for us. There is literally, 100% no difference in the two versions. value works just the same way—if whatever we would return from our $get function (aka our factory function) is always exactly the same, we can write even less code using value . For example, since we always return the same function for our greeting service, we can use value to define it, too:

Again, this is 100% identical to the other two methods we’ve used to define this function—it’s just a way to save some typing.

Now you probably noticed this annoying myMod.config(function($provide) < . >) thing I’ve been using. Since defining new providers (via any of the given methods above) is so common, AngularJS exposes the $provide methods directly on the module object, to save even more typing:

These all do the same thing as the more verbose app.config(. ) versions we used previously.

The one injectable I’ve skipped so far is constant . For now, it’s easy enough to say that it works just like value . We’ll see there’s one difference later.

To review, all these pieces of code are doing the exact same thing:

The injector is responsible for actually creating instances of our services using the code we provided via $provide (no pun intended). Any time you write a function that takes injected arguments, you’re seeing the injector at work. Each AngularJS application has a single $injector that gets created when the application first starts; you can get a hold of it by injecting $injector into any injectable function (yes, $injector knows how to inject itself!)

Once you have $injector , you can get an instance of a defined service by calling get on it with the name of the service. For example,

The injector is also responsible for injecting services into functions; for example, you can magically inject services into any function you have using the injector’s invoke method;

It’s worth noting that the injector will only create an instance of a service once. It then caches whatever the provider returns by the service’s name; the next time you ask for the service, you’ll actually get the exact same object.

So, it stands to reason that you can inject services into any function that is called with $injector.invoke . This includes

  • controller definition functions
  • directive definition functions
  • filter definition functions
  • the $get methods of providers (aka the factory definition functions)

Since constant s and value s always return a static value, they are not invoked via the injector, and thus you cannot inject them with anything.

You may be wondering why anyone would bother to set up a full-fledged provider with the provide method if factory , value , etc. are so much easier. The answer is that providers allow a lot of configuration. We’ve already mentioned that when you create a service via the provider (or any of the shortcuts Angular gives you), you create a new provider that defines how that service is constructed. What I didn’t mention is that these providers can be injected into config sections of your application so you can interact with them!

First, Angular runs your application in two phases—the config and run phases. The config phase, as we’ve seen, is where you can set up any providers as necessary. This is also where directives, controllers, filters, and the like get set up. The run phase, as you might guess, is where Angular actually compiles your DOM and starts up your app.

You can add additional code to be run in these phases with the myMod.config and myMod.run functions—each take a function to run during that specific phase. As we saw in the first section, these functions are injectable—we injected the built-in $provide service in our very first code sample. However, what’s worth noting is that during the config phase, only providers can be injected (with the exception of the services in the AUTO module— $provide and $injector ).

For example, the following is not allowed:

What you do have access to are any providers for services you’ve made:

There is one important exception: constant s, since they cannot be changed, are allowed to be injected inside config blocks (this is how they differ from value s). They are accessed by their name alone (no Provider suffix necessary).

Whenever you defined a provider for a service, that provider gets named serviceProvider , where service is the name of the service. Now we can use the power of providers to do some more complicated stuff!

Now we have a function on our provider called setText that we can use to customize our alert ; we can get access to this provider in a config block to call this method and customize the service. When we finally run our app, we can grab the greeting service, and try it out to see that our customization took effect.

Since this is a more complex example, here’s a working demonstration: http://jsfiddle.net/BinaryMuse/9GjYg/

You can inject things into controllers, but you can’t inject controllers into things. That’s because controllers aren’t created via the provider. Instead, there is a built-in Angular service called $controller that is responsible for setting up your controllers. When you call myMod.controller(. ) , you’re actually accessing this service’s provider, just like in the last section.

For example, when you define a controller like this:

What you’re actually doing is this:

Later, when Angular needs to create an instance of your controller, it uses the $controller service (which in turn uses the $injector to invoke your controller function so it gets its dependencies injected too).

Filters and Directives

filter and directive work exactly the same way as controller ; filter uses a service called $filter and its provider $filterProvider , while directive uses a service called $compile and its provider $compileProvider . Some links:

As per the other examples, myMod.filter and myMod.directive are shortcuts to configuring these services.

So, to summarize, any function that gets called with $injector.invoke can be injected into. This includes, but is not limited to:

  • controller
  • directive
  • factory
  • filter
  • provider $get (when defining provider as an object)
  • provider function (when defining provider as a constructor function)
  • service

The provider creates new services that can be injected into things. This includes:

That said, built-in services like $controller and $filter can be injected, and you can use those services to get hold of the new filters and controllers you defined with those methods (even though the things you defined aren’t, by themselves, able to be injected into things).

Other than that, any injector-invoked function can be injected with any provider-provided service—there is no restriction (other than the config and run differences listed herein).

AngularJS Dependency Injection

Through this part of the AngularJS tutorial you will learn about dependency injection and its example.


Understanding Dependency Injection

Dependency Injection in AngularJS can be defines as the software design pattern which defines the way the software components are dependent on each other. AngularJS provides a set of components that can be injected in the form of dependencies such as factory, value, constant, service, and provider.

Внедрение зависимостей в SignalR Dependency Injection in SignalR

Эта документация не для последней версии SignalR. This documentation isn’t for the latest version of SignalR. Взгляните на ASP.NET Core SignalR. Take a look at ASP.NET Core SignalR.

Версии программного обеспечения, используемого в этом разделе Software versions used in this topic

  • Visual Studio 2013 Visual Studio 2013
  • .NET 4.5 .NET 4.5
  • SignalR версии 2 SignalR version 2

Предыдущие версии этого раздела Previous versions of this topic

Сведения о более ранних версий SignalR, см. в разделе более старых версий SignalR. For information about earlier versions of SignalR, see SignalR Older Versions.

Вопросы и комментарии Questions and comments

Оставьте свои отзывы на том, как вам понравилось, и этот учебник и что можно улучшить в комментариях в нижней части страницы. Please leave feedback on how you liked this tutorial and what we could improve in the comments at the bottom of the page. Если у вас есть вопросы, которые не имеют отношения к руководству, их можно разместить форум по ASP.NET SignalR или StackOverflow.com. If you have questions that are not directly related to the tutorial, you can post them to the ASP.NET SignalR forum or StackOverflow.com.

Внедрение зависимостей является способ удаления жестких зависимостей между объектами, упрощая для замены зависимости объекта, либо для тестирования (с использованием макетов объектов) или для изменения поведения во время выполнения. Dependency injection is a way to remove hard-coded dependencies between objects, making it easier to replace an object’s dependencies, either for testing (using mock objects) or to change run-time behavior. Этом руководстве показано, как выполнить внедрения зависимостей для концентраторов SignalR. This tutorial shows how to perform dependency injection on SignalR hubs. Также показано, как использовать контейнеры IoC с SignalR. It also shows how to use IoC containers with SignalR. IoC-контейнер — это стандартная структура для внедрения зависимостей. An IoC container is a general framework for dependency injection.

Топ-пост этого месяца:  Пользователи ВКонтакте могут подавать объявления о продаже товаров

Что такое внедрение зависимостей? What is Dependency Injection?

Этот раздел можно пропустите, если вы уже знакомы с помощью внедрения зависимостей. Skip this section if you are already familiar with dependency injection.

Внедрение зависимостей (DI) — это шаблон, где объекты не отвечают за создание собственных зависимостей. Dependency injection (DI) is a pattern where objects are not responsible for creating their own dependencies. Ниже приведен простой пример для внедрения Зависимостей. Here is a simple example to motivate DI. Предположим, что у вас есть объект, который требуется для регистрации сообщений. Suppose you have an object that needs to log messages. Можно определить интерфейс ведения журнала: You might define a logging interface:

В объекте, можно создать ILogger запись сообщений в журнал: In your object, you can create an ILogger to log messages:

Это работает, но это не рекомендуется. This works, but it’s not the best design. Если вы хотите заменить FileLogger с другим ILogger реализации, нужно будет только изменить SomeComponent . If you want to replace FileLogger with another ILogger implementation, you will have to modify SomeComponent . Допустим, что много других объектов используйте FileLogger , необходимо изменить все из них. Supposing that a lot of other objects use FileLogger , you will need to change all of them. Или если необходимо внести FileLogger является одноэлементным множеством, также необходимо внести изменения в приложении. Or if you decide to make FileLogger a singleton, you’ll also need to make changes throughout the application.

Лучшим подходом является «внедрение» ILogger в объект — например, с помощью аргумента конструктора: A better approach is to «inject» an ILogger into the object—for example, by using a constructor argument:

Теперь объект не несет ответственности за выбора ILogger для использования. Now the object is not responsible for selecting which ILogger to use. Вы можете ILogger реализации без изменения объекты, зависящие от нее. You can switch ILogger implementations without changing the objects that depend on it.

Такая модель называется внедрение через конструктор. This pattern is called constructor injection. Другой шаблон — внедрение метод задания, где можно устанавливать для зависимости через метод или свойство. Another pattern is setter injection, where you set the dependency through a setter method or property.

Внедрение простого зависимостей в SignalR Simple Dependency Injection in SignalR

Рассмотрим приложение чата из учебника начало работы с SignalR. Consider the Chat application from the tutorial Getting Started with SignalR. Ниже показан класс центра из этого приложения: Here is the hub class from that application:

Предположим, что вам нужно хранить сообщения чата на сервере перед их отправкой. Suppose that you want to store chat messages on the server before sending them. Можно определить интерфейс, который абстрагирует эту функцию и использовать внедрение Зависимостей для вставки интерфейса в ChatHub класса. You might define an interface that abstracts this functionality, and use DI to inject the interface into the ChatHub class.

Единственная проблема состоит, что приложение SignalR непосредственно не создать концентраторы; SignalR создаст их самостоятельно. The only problem is that a SignalR application does not directly create hubs; SignalR creates them for you. По умолчанию SignalR ожидает, что для класса концентратора конструктор без параметров. By default, SignalR expects a hub class to have a parameterless constructor. Тем не менее можно легко зарегистрировать функцию для создания экземпляров концентраторов и использовать эту функцию для выполнения внедрения Зависимостей. However, you can easily register a function to create hub instances, and use this function to perform DI. Зарегистрируйте функцию с помощью метода GlobalHost.DependencyResolver.Register. Register the function by calling GlobalHost.DependencyResolver.Register.

Теперь SignalR будет вызывать это анонимная функция, каждый раз, когда необходимо создать ChatHub экземпляра. Now SignalR will invoke this anonymous function whenever it needs to create a ChatHub instance.

Контейнеры IoC IoC Containers

Предыдущий код годится для простых случаях. The previous code is fine for simple cases. Но все равно требовалось написать следующее: But you still had to write this:

В сложных приложениях с много зависимостей может потребоваться написать немало этот код «подключения». In a complex application with many dependencies, you might need to write a lot of this «wiring» code. Этот код может быть трудно поддерживать, особенно в том случае, если зависимости являются вложенными. This code can be hard to maintain, especially if dependencies are nested. Это также трудно модульного теста. It is also hard to unit test.

Одним из решений является использование IoC-контейнер. One solution is to use an IoC container. IoC-контейнер — это программный компонент, который отвечает за управление зависимостями. Зарегистрируйте типов в контейнере и затем использовать для создания объектов контейнера. An IoC container is a software component that is responsible for managing dependencies.You register types with the container, and then use the container to create objects. Контейнер автоматически определяет отношение зависимость. The container automatically figures out the dependency relations. Кроме того, множество контейнеров инверсии управления позволяют управлять времени существования объектов и области. Many IoC containers also allow you to control things like object lifetime and scope.

«IoC» означает «инверсии элемента управления», который является общий шаблон, когда платформа вызывает в код приложения. «IoC» stands for «inversion of control», which is a general pattern where a framework calls into application code. Контейнер IoC создает объектов, который «инвертирует» обычного потока управления. An IoC container constructs your objects for you, which «inverts» the usual flow of control.

Использование контейнеров IoC в SignalR Using IoC Containers in SignalR

Приложения чата, вероятно, слишком простой использовать преимущества контейнер IoC. The Chat application is probably too simple to benefit from an IoC container. Вместо этого давайте взглянем на StockTicker образца. Instead, let’s look at the StockTicker sample.

Образец StockTicker определяет два основных класса: The StockTicker sample defines two main classes:

  • StockTickerHub : Класс концентратора, который управляет клиентских подключений. StockTickerHub : The hub class, which manages client connections.
  • StockTicker : Единственный экземпляр, который содержит цены акций и периодически обновлять их. StockTicker : A singleton that holds stock prices and periodically updates them.

StockTickerHub хранит ссылку на StockTicker одноэлементным множеством, хотя StockTicker хранит ссылку на IHubConnectionContext для StockTickerHub . StockTickerHub holds a reference to the StockTicker singleton, while StockTicker holds a reference to the IHubConnectionContext for the StockTickerHub . Использует этот интерфейс для взаимодействия с StockTickerHub экземпляров. It uses this interface to communicate with StockTickerHub instances. (Дополнительные сведения см. в разделе передача сообщений с сервера с помощью SignalR.) (For more information, see Server Broadcast with ASP.NET SignalR.)

Можно использовать контейнер IoC для немного клубка эти зависимости. We can use an IoC container to untangle these dependencies a bit. Во-первых давайте упростим StockTickerHub и StockTicker классы. First, let’s simplify the StockTickerHub and StockTicker classes. В следующем коде я закомментирован частей, нам не нужен. In the following code, I’ve commented out the parts that we don’t need.

Удалите конструктор без параметров из StockTickerHub . Remove the parameterless constructor from StockTickerHub . Вместо этого всегда используется DI создайте концентратор. Instead, we will always use DI to create the hub.

Для StockTicker удалите одноэлементный экземпляр. For StockTicker, remove the singleton instance. Позже мы будем использовать контейнер IoC, управление временем существования StockTicker. Later, we’ll use the IoC container to control the StockTicker lifetime. Кроме того не открытый конструктор. Also, make the constructor public.

Далее мы можем выполнить рефакторинг кода путем создания интерфейса для StockTicker . Next, we can refactor the code by creating an interface for StockTicker . Мы будем использовать этот интерфейс для отделения StockTickerHub из StockTicker класса. We’ll use this interface to decouple the StockTickerHub from the StockTicker class.

Visual Studio делает этот вид рефакторинга просто. Visual Studio makes this kind of refactoring easy. Откройте файл StockTicker.cs, щелкните правой кнопкой мыши StockTicker объявление класса и выберите рефакторинг . Извлечение интерфейса. Open the file StockTicker.cs, right-click on the StockTicker class declaration, and select Refactor . Extract Interface.

В извлечение интерфейса диалоговое окно, нажмите кнопку выбрать все. In the Extract Interface dialog, click Select All. Оставьте остальные значения по умолчанию. Leave the other defaults. Нажмите кнопку ОК. Click OK.

Visual Studio создает новый интерфейс с именем IStockTicker , а также изменяет StockTicker для наследования от IStockTicker . Visual Studio creates a new interface named IStockTicker , and also changes StockTicker to derive from IStockTicker .

Откройте файл IStockTicker.cs и изменить интерфейс для открытый. Open the file IStockTicker.cs and change the interface to public.

В StockTickerHub измените два экземпляра StockTicker для IStockTicker : In the StockTickerHub class, change the two instances of StockTicker to IStockTicker :

Создание IStockTicker интерфейса не является обязательным, но я хотел показать, как внедрение Зависимостей позволяет сократить взаимозависимости между компонентами приложения. Creating an IStockTicker interface isn’t strictly necessary, but I wanted to show how DI can help to reduce coupling between components in your application.

Добавьте библиотеку Ninject Add the Ninject Library

Существует множество контейнеров инверсии управления открытым исходным кодом для .NET. There are many open-source IoC containers for .NET. В этом учебнике я использую Ninject. For this tutorial, I’ll use Ninject. (Включить других популярных библиотек Castle Windsor, Spring.Net, Autofac, Unity, и StructureMap .) (Other popular libraries include Castle Windsor, Spring.Net, Autofac, Unity, and StructureMap.)

С помощью диспетчера пакетов NuGet для установки Ninject библиотеки. Use NuGet Package Manager to install the Ninject library. В Visual Studio из средства меню выберите диспетчер пакетов NuGet > консоль диспетчера пакетов. In Visual Studio, from the Tools menu select NuGet Package Manager > Package Manager Console. В окне консоли диспетчера пакетов введите следующую команду: In the Package Manager Console window, enter the following command:

Замените Сопоставитель зависимостей SignalR Replace the SignalR Dependency Resolver

Чтобы использовать Ninject в SignalR, создайте класс, производный от DefaultDependencyResolver. To use Ninject within SignalR, create a class that derives from DefaultDependencyResolver.

Этот класс переопределяет GetService и GetServices методы DefaultDependencyResolver. This class overrides the GetService and GetServices methods of DefaultDependencyResolver. SignalR эти методы вызываются для создания различных объектов во время выполнения, включая экземпляры центра, а также различные службы, используемые внутри SignalR. SignalR calls these methods to create various objects at runtime, including hub instances, as well as various services used internally by SignalR.

  • GetService метод создает один экземпляр типа. The GetService method creates a single instance of a type. Переопределите этот метод для вызова ядра Ninject TryGet метод. Override this method to call the Ninject kernel’s TryGet method. Если этот метод возвращает значение null, переключиться на Сопоставитель по умолчанию. If that method returns null, fall back to the default resolver.
  • GetServices метод создает коллекцию объектов указанного типа. The GetServices method creates a collection of objects of a specified type. Переопределите этот метод, чтобы объединить результаты из Ninject с результатами из Сопоставитель по умолчанию. Override this method to concatenate the results from Ninject with the results from the default resolver.

Настройка привязок Ninject Configure Ninject Bindings

Теперь мы будем использовать для объявления привязки типов Ninject. Now we’ll use Ninject to declare type bindings.

Откройте класс Startup.cs приложения (либо созданного вручную согласно инструкциям пакета в readme.txt , или который был создан путем добавления проверки подлинности в проект). Open your application’s Startup.cs class (that you either created manually as per the package instructions in readme.txt , or that was created by adding authentication to your project). В Startup.Configuration метод, создайте контейнер Ninject, который вызывает Ninject ядра. In the Startup.Configuration method, create the Ninject container, which Ninject calls the kernel.

Создайте экземпляр сопоставителя наших пользовательскую зависимость: Create an instance of our custom dependency resolver:

Создать привязку для IStockTicker следующим образом: Create a binding for IStockTicker as follows:

Этот код говорит две вещи. This code is saying two things. Во-первых, каждый раз, когда приложение должно IStockTicker , ядро следует создать экземпляр StockTicker . First, whenever the application needs an IStockTicker , the kernel should create an instance of StockTicker . Во-вторых, StockTicker класс должен быть созданный объект в виде одноэлементного объекта. Second, the StockTicker class should be a created as a singleton object. Ninject будет создать один экземпляр объекта и возвращают один и тот же экземпляр для каждого запроса. Ninject will create one instance of the object, and return the same instance for each request.

Создать привязку для IHubConnectionContext следующим образом: Create a binding for IHubConnectionContext as follows:

Этот код создает анонимную функцию, которая возвращает IHubConnection. This code creates an anonymous function that returns an IHubConnection. WhenInjectedInto метод указывает Ninject, чтобы использовать эту функцию только в том случае, при создании IStockTicker экземпляров. The WhenInjectedInto method tells Ninject to use this function only when creating IStockTicker instances. Причина в том, что создает SignalR IHubConnectionContext экземпляров на внутреннем уровне и мы не хотим переопределить как SignalR создает их. The reason is that SignalR creates IHubConnectionContext instances internally, and we don’t want to override how SignalR creates them. Эта функция применяется только к нашей StockTicker класса. This function only applies to our StockTicker class.

Передайте в сопоставителе зависимостей в MapSignalR метод путем добавления конфигурации концентратора: Pass the dependency resolver into the MapSignalR method by adding a hub configuration:

Обновите метод Startup.ConfigureSignalR в классе запуска образца, используя новый параметр: Update the Startup.ConfigureSignalR method in the sample’s Startup class with the new parameter:

Теперь SignalR будет использовать сопоставителя, указанного в MapSignalR, вместо Сопоставитель по умолчанию. Now SignalR will use the resolver specified in MapSignalR, instead of the default resolver.

Добавить комментарий