Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP.NET MVC Урок 1-F / ASP.NET MVC Урок 2

.pdf
Скачиваний:
45
Добавлен:
09.03.2016
Размер:
243.35 Кб
Скачать

$63 1(7 09& ǻȘȖȒ 'HSHQGHQF\ ,QMHFWLRQtutorial

ASP*, .NET*

Цель урока: Изучение DI (Dependency Injection). Пример на Ninject, Unity, Autofac и Winsor.

Во многих случаях, один и тот же экземпляр класса используется в вашем приложении в разных модулях. Простым способом реализации является применение шаблона Одиночка (Singleton).

Но рассмотрим эту ситуацию с другой стороны. Так как данный объект создается при первом обращении к нему, мы не можем контролировать его время жизни. При модульном тестировании (unit­test) нет необходимости использовать этот объект (или это может быть невозможно). Чтобы избежать этого, мы не напрямую вызываем объект, а через интерфейс. И реальный экземпляр класса, и экземпляр­заглушка для тестирования будут реализовывать этот интерфейс. А логику создания мы поручаем DI­контейнеру.

Например, до использования сервиса. Опишем пару классов, интерфейс IWeapon с методом Kill, два класса реализации Bazuka и Sword, и класс Warrior, который пользуется оружием:

SXEOLF LQWHUIDFH ,:HDSRQ

^

YRLG .LOO

`

SXEOLF FODVV %D]XND ,:HDSRQ

^

SXEOLF YRLG .LOO

^

&RQVROH :ULWH/LQH%,* %$'$%80

`

`

SXEOLF FODVV 6ZRUG ,:HDSRQ

^

SXEOLF YRLG .LOO

^

&RQVROH :ULWH/LQH&KXN FKXFN

`

`

SXEOLF FODVV :DUULRU

^

UHDGRQO\,:HDSRQ :HDSRQ

SXEOLF :DUULRU,:HDSRQ ZHDSRQ

^

WKLV:HDSRQ ZHDSRQ

`

SXEOLF YRLG .LOO

^

:HDSRQ .LOO

`

`

Используем это:

FODVV 3URJUDP

^

VWDWLF YRLG 0DLQ VWULQJ>@ DUJV

^

:DUULRU ZDUULRU QHZ:DUULRUQHZ%D]XND

ZDUULRU .LOO

&RQVROH 5HDG/LQH

`

`

Читаем между строк. Создаем воина и даем ему базуку, он идет и убивает. В консоли получаем:

%,* %$'$%80

Заметим, что у нас нет проверки на null в строке

:HDSRQ .LOO

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

Суть DI – поручить выдачу оружия другому модулю.

Подключаем Ninject:

,QVWDOO 3DFNDJH 1LQMHFW

Создаем модуль, который занимается выдачей оружия:

SXEOLF FODVV :HDSRQ1LQMHFW0RGXOH 1LQMHFW0RGXOH

^

SXEOLF RYHUULGH YRLG /RDG

^

WKLV%LQG ,:HDSRQ! 7R 6ZRUG!

`

`

Что буквально значит: «если попросят оружие – то выдайте мечи». Создаем «сервис­локатор» и пользуемся оружием:

FODVV 3URJUDP

^

SXEOLF VWDWLF,.HUQHO$SS.HUQHO

VWDWLF YRLG 0DLQ VWULQJ>@ DUJV

^

$SS.HUQHO QHZ6WDQGDUG.HUQHOQHZ:HDSRQ1LQMHFW0RGXOH

YDUZDUULRU $SS.HUQHO *HW :DUULRU!

ZDUULRU .LOO

&RQVROH 5HDG/LQH

`

`

Как видно, объект warrior мы создаем не с помощью конструкции new, а через$SS.HUQHO *HW !. При создании AppKernel, мы передаем в качестве конструктора модуль, отвечающий за выдачу оружия (в данном случае это меч). Любой объект, который мы пытаемся получить через $SS.HUQHO *HW, будет (по мере возможности) проинициализирован, если существуют модули, которые знают, как это делать.

Другой момент применения, когда объект :DUULRU не берет с собой оружие каждый раз, а при не обнаружении оного обращается к сервису локатору и получает его:

SXEOLF FODVV 2WKHU:DUULRU

^

SULYDWH,:HDSRQ BZHDSRQ

SXEOLF,:HDSRQ :HDSRQ

^

JHW

^

LIBZHDSRQ QXOO

^

BZHDSRQ 3URJUDP$SS.HUQHO *HW ,:HDSRQ!

`

UHWXUQBZHDSRQ

`

`

SXEOLF YRLG .LOO

^

:HDSRQ .LOO

`

`

Исполняем:

YDURWKHU:DUULRU QHZ2WKHU:DUULRU

RWKHU:DUULRU .LOO

Наш воин получает оружие по прямым поставкам – супер!

В Ninject есть еще одна очень хорошая деталь. Если свойство (SXEOLF SURSHUW\)

помечено >,QMHFW@, то при создании класса через $SS.HUQHO *HW ! – поле инициализуется сервисом­локатором:

SXEOLF FODVV $QRWKHU:DUULRU

^

>,QMHFW@

SXEOLF,:HDSRQ :HDSRQ ^JHW VHW`

SXEOLF YRLG .LOO

^

:HDSRQ .LOO

`

`

YDUDQRWKHU:DUULRU $SS.HUQHO *HW$QRWKHU:DUULRU!

DQRWKHU:DUULRU .LOO

Unity

Абсолютно всё то же: Установка

,QVWDOO 3DFNDJH 8QLW\

Инициализация сервиса локатора (Container)

&RQWDLQHU QHZ8QLW\&RQWDLQHU

Регистрация типа

&RQWDLQHU 5HJLVWHU7\SHW\SHRI,:HDSRQW\SHRI%D]XND

Получение объекта и использование:

YDUZDUULRU &RQWDLQHU 5HVROYH :DUULRU!

ZDUULRU .LOO

Кроме того, у Unity есть класс­одиночка 6LQJOHWRQ 6HUYLFH/RFDWRU, который регистрирует контейнер и позволяет получить доступ к сервисам из любого места.

YDUVHUYLFH3URYLGHU QHZ8QLW\6HUYLFH/RFDWRU &RQWDLQHU

6HUYLFH/RFDWRU 6HW/RFDWRU3URYLGHU ! VHUYLFH3URYLGHU

Хитрый 2WKHU:DUULRU теперь так получает оружие:

SXEOLF FODVV 2WKHU:DUULRU

^

SULYDWH,:HDSRQ BZHDSRQ

SXEOLF,:HDSRQ :HDSRQ

^

JHW

^

LIBZHDSRQ QXOO

^

BZHDSRQ 6HUYLFH/RFDWRU &XUUHQW *HW,QVWDQFH ,:HDSRQ!

`

UHWXUQBZHDSRQ

`

`

SXEOLF YRLG .LOO

^

:HDSRQ .LOO

`

`

Autofac

Так же, собственно, всё и происходит: Установка

,QVWDOO 3DFNDJH$XWRIDF

Инициализация строителя сервиса­локатора (&RQWDLQHU%XLOGHU) – нет­нет, это еще не сам контейнер, это — как модули

YDUEXLOGHU QHZ&RQWDLQHU%XLOGHU

Регистрация типов. Надо зарегистрировать все необходимые классы, потому что создание экземпляров незарегистрированных классов тут не реализован.

EXLOGHU 5HJLVWHU7\SH %D]XND!

EXLOGHU 5HJLVWHU7\SH :DUULRU!

EXLOGHU 5HJLVWHU ,:HDSRQ! [ ! [ 5HVROYH %D]XND!

Создание сервиса локатора (Container)

YDUFRQWDLQHU EXLOGHU %XLOG

Получение объекта и использование:

YDUZDUULRU FRQWDLQHU 5HVROYH :DUULRU!

ZDUULRU .LOO

Castle Windsor

Установка

,QVWDOO 3DFNDJH &DVWOH :LQGVRU

Инициализация сервиса­локатора

YDUFRQWDLQHU QHZ:LQGVRU&RQWDLQHU

Регистрация типов. Аналогична как и в Autofac.

FRQWDLQHU 5HJLVWHU &RPSRQHQW )RU ,:HDSRQ! ,PSOHPHQWHG%\ %D]XND!

&RPSRQHQW )RU :DUULRU! ,PSOHPHQWHG%\ :DUULRU!

Получение объекта и использование:

YDUZDUULRU FRQWDLQHU 5HVROYH :DUULRU!

ZDUULRU .LOO

Маленький подитог

На самом деле, реализации Dependency Injection не сильно, но всё же отличаются. Некоторые поддерживают инициализацию в :HE FRQILJ$SS FRQILJ файлах. Некоторые, задают правила для инициализации, как мы сейчас посмотрим на расширении Ninject для asp.net mvc – это касается инициализации сервиса­локатора как генератора общих объектов, так и отдельно для каждого потока или web­запросе.

Объекты областей (Ninject)

В Ninject можно задать несколько способов инициализации получения объекта из класса. Если мы работаем в различных контекстах (например, в разных потоках (Thread)), то объекты должны быть использованы разные. Тем самым, поддерживается масштабируемость и гибкость приложения.

Облас

Метод

Объяснение

ть

связывания

 

 

 

 

Време

,Q7UDQVLHQW

Объект класса будет создаваться по каждому

нный

6FRSH

требованию (метод по умолчанию).

Одино

,Q6LQJOHWRQ

Объект класса будет создан один раз и будет

чка

6FRSH

использоваться повторно.

Поток

,Q7KUHDG6FR

Один объект на поток.

 

SH

 

Запрос

,Q5HTXHVW6F

Один объект будет на каждый web­запрос

 

RSH

 

Lifetime Manager в Unity

В Unity для задачи правил инициализации используется реализация абстрактного класса

LifetimeManager.

Происходит это так:

BFRQWDLQHU 5HJLVWHU7\SH 'E&RQWH[W 6DYHFDVK7UDYHO&RQWH[W!QHZ3HU5HTXHVW/LIHWLPH0DQDJHU

Где PerRequestLifetimeManager – это реализация LifetimeManager:

SXEOLF FODVV 3HU5HTXHVW/LIHWLPH0DQDJHU /LIHWLPH0DQDJHU

^

VXPPDU\!

.H\ WR VWRUH GDWD

VXPPDU\!

SULYDWH UHDGRQO\ VWULQJBNH\ 6WULQJ )RUPDW6LQJOHWRQ3HU5HTXHVW^ `*XLG 1HZ*XLG

VXPPDU\!

5HWULHYH D YDOXH IURP WKH EDFNLQJ VWRUH DVVRFLDWHG ZLWK WKLV /LIHWLPH SROLF\

VXPPDU\!

UHWXUQV!

WKH REMHFW GHVLUHG RU QXOO LI QR VXFK REMHFW LV FXUUHQWO\ VWRUHG

UHWXUQV!

SXEOLF RYHUULGH REMHFW *HW9DOXH

^

LI+WWS&RQWH[W &XUUHQW QXOO +WWS&RQWH[W &XUUHQW ,WHPV &RQWDLQV BNH\

UHWXUQ+WWS&RQWH[W &XUUHQW ,WHPV>BNH\@

UHWXUQ QXOO

`

VXPPDU\!

6WRUHV WKH JLYHQ YDOXH LQWR EDFNLQJ VWRUH IRU UHWULHYDO ODWHU

VXPPDU\!

SDUDP QDPH QHZ9DOXH !7KH REMHFW EHLQJ VWRUHGSDUDP!

SXEOLF RYHUULGH YRLG 6HW9DOXH REMHFWQHZ9DOXH

^

LI+WWS&RQWH[W &XUUHQW QXOO

+WWS&RQWH[W &XUUHQW ,WHPV>BNH\@ QHZ9DOXH

`

VXPPDU\!

5HPRYH WKH JLYHQ REMHFW IURP EDFNLQJ VWRUH

VXPPDU\!

SXEOLF RYHUULGH YRLG 5HPRYH9DOXH

^

LI+WWS&RQWH[W &XUUHQW QXOO +WWS&RQWH[W &XUUHQW ,WHPV &RQWDLQV BNH\

+WWS&RQWH[W &XUUHQW ,WHPV 5HPRYH BNH\

`

`

Суть. Все объекты хранятся в +WWS&RQWH[W &XUUHQW ,WHPV>BNH\@ и выдаются только, если уже находятся в том же контексте (+WWS&RQWH[W &XUUHQW). В ином случае, создается новый объект. Если текущий контекст (+WWS&RQWH[W &XUUHQW) в области кода не существует (используем такой/LIHWLPH0DQDJHUв консольном приложении или в отдельном потоке) – то данный контейнер не будет работать.

Использование Ninject в asp.net mvc

Устанавливаем Ninject в среду asp.net mvc. Отдельно создаем свой проект LessonProject,

создадим там HomeController с методом и view Index. (/Contollers/HomeController.cs):

SXEOLF FODVV +RPH&RQWUROOHU &RQWUROOHU

^

SXEOLF $FWLRQ5HVXOW,QGH[

^

UHWXUQ9LHZ

`

`

И (/Views/Home/Index.cshtml):

#^

9LHZ%DJ 7LWOH /HVVRQ3URMHFW

/D\RXW a 9LHZV 6KDUHG B/D\RXW FVKWPO

`

K!/HVVRQ3URMHFWK!

Запускаем – работает.

Примечание: В дальнейшем мы будем переносить этот проект в последующие уроки.

Теперь установим модуль Ninject и Ninject.MVC3 для этого проекта.

,QVWDOO 3DFNDJH 1LQMHFW 09&

Добавляем класс в папку App_Start (/App_Start/NinjectWebCommon.cs):

>DVVHPEO\ :HE$FWLYDWRU 3UH$SSOLFDWLRQ6WDUW0HWKRGW\SHRI/HVVRQ3URMHFW$SSB6WDUW 1LQMHFW:HE&RPPR Q6WDUW@ >DVVHPEO\ :HE$FWLYDWRU$SSOLFDWLRQ6KXWGRZQ0HWKRG$WWULEXWHW\SHRI/HVVRQ3URMHFW$SSB6WDUW 1LQMHFW :HE&RPPRQ6WRS@

QDPHVSDFH /HVVRQ3URMHFW$SSB6WDUW

^

XVLQJ6\VWHP

XVLQJ6\VWHP :HE

XVLQJ0LFURVRIW :HE ,QIUDVWUXFWXUH '\QDPLF0RGXOH+HOSHU

XVLQJ1LQMHFW

XVLQJ1LQMHFW :HE &RPPRQ

SXEOLF VWDWLF FODVV 1LQMHFW:HE&RPPRQ

^

SULYDWH VWDWLF UHDGRQO\%RRWVWUDSSHU ERRWVWUDSSHU QHZ%RRWVWUDSSHU

VXPPDU\!

6WDUWV WKH DSSOLFDWLRQ

VXPPDU\!

SXEOLF VWDWLF YRLG 6WDUW

^

'\QDPLF0RGXOH8WLOLW\ 5HJLVWHU0RGXOHW\SHRI2QH3HU5HTXHVW+WWS0RGXOH

'\QDPLF0RGXOH8WLOLW\ 5HJLVWHU0RGXOHW\SHRI1LQMHFW+WWS0RGXOH

ERRWVWUDSSHU ,QLWLDOL]H &UHDWH.HUQHO

`

VXPPDU\!

6WRSV WKH DSSOLFDWLRQ

VXPPDU\!

SXEOLF VWDWLF YRLG 6WRS

^

ERRWVWUDSSHU 6KXW'RZQ

`

VXPPDU\!

&UHDWHV WKH NHUQHO WKDW ZLOO PDQDJH \RXU DSSOLFDWLRQ

VXPPDU\!

UHWXUQV!7KH FUHDWHG NHUQHOUHWXUQV!

SULYDWH VWDWLF,.HUQHO&UHDWH.HUQHO

^

YDUNHUQHO QHZ6WDQGDUG.HUQHO

NHUQHO %LQG )XQF ,.HUQHO!! 7R0HWKRG FW[ ! !QHZ%RRWVWUDSSHU .HUQHO

NHUQHO %LQG ,+WWS0RGXOH! 7R +WWS$SSOLFDWLRQ,QLWLDOL]DWLRQ+WWS0RGXOH!

5HJLVWHU6HUYLFHV NHUQHO

UHWXUQNHUQHO

`

VXPPDU\!

/RDG \RXU PRGXOHV RU UHJLVWHU \RXU VHUYLFHV KHUH

VXPPDU\!

SDUDP QDPH NHUQHO !7KH NHUQHOSDUDP!

SULYDWH VWDWLF YRLG 5HJLVWHU6HUYLFHV,.HUQHO NHUQHO

^

`

`

`

В RegisterServices мы добавляем инициализацию своих сервисов. Для начала добавим шутливый IWeapon, а в дальнейшем еще будем возвращаться к этому методу для регистрации других сервисов:

SXEOLF LQWHUIDFH ,:HDSRQ

^

VWULQJ .LOO

`

«

SXEOLF FODVV %D]XND ,:HDSRQ

^

SXEOLF VWULQJ .LOO

^

UHWXUQ %,* %$'$%80

`

Соседние файлы в папке ASP.NET MVC Урок 1-F