Skip to content
March 1, 2014 / ahriman hpc mode

Блог переехал на http://blogs.msdn.com/b/albe

 

January 3, 2014 / ahriman hpc mode

Курс–дело 2013 года

Наконец-то выложили (раньше, на самом деле, но после моей поездки Сибирь-Америка-Польша-Россия-Америка-Сибирь только руки дошли написать) мой учебный курс, над которым я работал вторую половину 2013 года, и этот курс воистину воплотил собой все мое бытие как MVP. Курс можно найти на http://www.microsoftvirtualacademy.com/training-courses/windows-azure-for-app-development-and-infrastructure-services#?fbid=4rnkEZ-FAwv

 

Оставайтесь настроенными, так сказать. Понемногу готовится мой новый проект, который станет проектом 2014 года.

June 25, 2013 / ahriman hpc mode

Рассуждая о сертификации Microsoft. Зачем, как, почему, какие проблемы? Пример подготовки плана к экзамену 70-487.

Добрый день, уважаемые коллеги.

В этой статье, посвященной сертификации, мы поговорим о том, зачем нужна сертификация, какая она бывает у Microsoft, а также разберем проблемы, которые возникают во время процесса сдачи экзаменов на сертификаты.

Зачем?

Итак, для того, чтобы зарегистрироваться на сертификационный экзамен Microsoft, необходимо прежде всего выяснить, зачем это нужно конкретно вам. Уходя от банальных причин, которые в принципе недоказуемы (например, “работодатели смотрят на количество сертификатов” без перечисления этих работодателей, это игра на некоторых секретных знаниях, при этом касающихся только определенной части работодателей), расскажу об одной причину, по которой сдаю экзамены я.

Причина, по которой я считаю нужным для себя сдавать сертификационные экзамены – это подтверждение уже существующей планки знаний и умений или установление новой. После определенного опыта использования любой интересной технологии часто не хочется терять этот опыт из-за того, что он не уложился в голове или уложился неструктурированно. Многие люди, даже имея за плечами многолетний опыт, часто не умеют подходить к изучению нового методически, так, чтобы новые знания не остались в пределах одного приложения, написанного с их использованием. Как раз здесь прекрасно подходит подготовка и сдача сертификационных экзаменов. Сдача экзамена подразумевает, что у кандидата уже сформировалась определенная устойчивая база знаний, изрядно дополненная реальным практическим опытом использования (подход к сдаче экзаменов, заключающийся в зубрении теории, не выдерживает критики, так как много вопросов связано именно с практическим опытом кандидата). Как же ее сформировать? Ведь даже профессиональные разработчики порой “плавают” в, казалось бы, основах тех технологий, которые они изучают. Ответ очень прост – настроиться на сдачу сертификационного экзамена от вендора.

Настроившись на сдачу экзамена, сказав, что “я хочу сдать этот экзамен для того, чтобы [X]“, где [X] – причина, следует, что логично, перейти к причине.

Я уверен, что самая важная причина добровольной сдачи каких бы то ни было экзаменов должна формулироваться как “я хочу подтвердить свои знания либо увидеть, где их не хватает”. Статусы – это для удовлетворения внешних клиентов. Подтверждение знаний – для внутреннего клиента самого главного потребителя – вас.

Зачем это делать? Зачем подтверждать свои знания? Зачем уходить в тот процесс, который в случае с IT грозит стать бесконечным? Для того, чтобы не было стыдно, когда в резюме есть строчка “профессиональный разработчик на WCF с опытом 5 лет”, на интервью же задают вопрос типа “как можно сделать так, чтобы запросы, приходящие в веб-сервис, выполнялись параллельно внутри одного созданного экземпляра сервиса?”, а ответ неизвестен. Кто-то может сказать, что “я не сталкивался с этим, поэтому не знаю.” или “это сценарий, который скорее всего никогда не пригодится”. Подобные ответы я слышал не раз, и всякий раз они сопутствовали незнанию _базовых_ основ технологии. Зачем знать о том, что такое Frame Relay, ведь им никто не пользуется? Зачем знать, что такое msbuild, если уже есть Visual Studio? Подобные вопросы возникают постоянно. И последствия у них могут быть такие же, как незнание того, как строить дом, не зная, как правильно делать фундамент.

Причина “подтверждения своих знаний с помощью сдачи сертификационного экзамена” частично решает проблему тем, что во время подготовки к экзамену приходится читать большое количество материалов, которые неизбежно, по мере обучения, структурируются в единый выстроенный пласт знаний. Главное в этом процессе – не пролистывать материал книгами, отмечая, что “это я знаю, и это тоже”, но читать вдумчиво, по возможности коспектируя прочитанное и составляя план дальнейших действий.

Разумеется, что этот подход часто критикуется апологетами быстрого обучения, утверждающими, что, если “работал 5 лет с продуктом, то легко сдашь экзамен”. Может, и получится сдать. Волей случая в экзамене без подготовки могут попасться те вопросы, на которые кандидат гарантированно знает ответ. Но решает ли это задачу, ради которой сдается экзамен – подтвердить свои знания? С одной стороны, решает. С другой – пробелы в знаниях так и остаются пробелами.

Итак, решив с причиной, необходимо перейти к тщательному составлению списка литературы, которая может помочь в сдаче экзамена, как подготовительной, так и часто – документации, например, к API. Например, практически ко всем экзаменам Microsoft есть специальные книги, в участии которых принимают известные специалисты, которые являются, по своей сути, быстрой “пробежкой” по технологии с акцентом там, где это может быть полезно. Рассматривать их как единственный ресурс не стоит, скорее – как либо ресурс на первое прочтение (когда нужно понять, где пробелы в знаниях), либо, наоборот, в качестве чтения в последнюю ночь. Замечательной особенностью экзаменов Microsoft является наличие подробного описания к каждому экзамену, включая ссылки на некоторое количество подготовительных материалов и на покупку книг.

После этого же остается изучать литературу до последнего дня перед экзаменом. Последний день перед экзаменом лично я больше ничего не читаю, не готовлю и даже не заглядываю в план. Знаниям нужен тайм-аут, чтобы уложиться.

Как?

Типичной просьбой, который мне задают на всех курсах, которые я веду, является просьба рассказать о том, что такое MCTS, MCPD и иже с ними. Кто-то не знает даже этих аббревиатур, кто-то знает их расшифровку, кто-то даже предварительно представляет, как выглядит интересующий сертификационный трек. Но многие-таки попадают в ловушку, не читая подробно условия получения различных статусов. Давайте кратко рассмотрим их и дадим характеристику каждому из соответствующих экзаменов. Рассматривать будем сертификационный трек Web Developer.
Итак, решено сдавать сертификационный экзамен на веб-разработчика. Открывается страница Microsoft Learning, начинает изучаться соответствующий трек, и тут возникает вопрос – есть два статуса, Microsoft Certified Technical Specialist и Microsoft Certified Professional Developer. И там и там необходимо сдавать экзамены. Так зачем сдавать на MCTS, если можно сразу сдать 70-519 (PRO: Designing and Developing Web Applications Using Microsoft .NET Framework 4) и получить соответствующий статус?
Ошибка кроется в терминах. Сдав экзамен MCPD, вы… сдадите экзамен MCPD. Сдача одного этого экзамена не дает статус Professional Web Developer. Каждый статус уровня Professional состоит из набора экзаменов MCTS + одного экзамена, содержащего вопросы и кейсы непосредственно профессионального уровня. И только после сдачи всех низлежащих MCTS и одного экзамена MCPD кандидат получает статус MCPD. И, вместе с ним, у кандидата появляется пять статусов – по одному на MCTS и MCPD. Никак иначе. Бывают экзамен типа Upgrade, когда можно обновить свой статус до новой версии продукта.

Это необходимо четко понимать.

Различия между экзаменами MCTS и MCPD заключаются в одной большой разнице уровня подготовки кандидата, что отражается на вопросах в тестах. Так, в MCTS проверяются как моменты общего назначения (например, для чего предназначена та или иная функция в Windows Server, или вышеупомянутый вопрос про обрабатывающиеся параллельно запросы), так и вещи, касающиеся знания конкретных реализаций в технологии – например,  определение результата той или иной команды – подобные вопросы часто содержатся как в сертификационных треках для разработчиков, так и треках для ITPro. В экзаменах уровня Professional же фокус вопросов сдвигается в сторону практического опыта разработки либо развертывания (в случае ITPro). Кроме этого, в экзаменах уровня Professional содержатся так называемые тестлеты – отдельные семантические модули, в которых предлагается изучить сценарий и ответить на вопросы конкретно по этому сценарию. Например, “у вас есть распределенная инфраструктура, и несколько филиалов, в которых нужно развернуть N серверов с ролью S” или “вы хотите мигрировать большое корпоративное приложение с ASP.NET Web Forms на ASP.NET MVC”. Сценарии абсолютно выдуманные и упрощенные – в реальных экзаменах сценарии  могут быть гораздо сложнее, и по наитию ответить правильно можно только по случайности. Тестлеты – изюминка экзаменов Professional, и самая сложная их часть, так как именно в ней может содержаться тот сценарий, который ни разу не встречался и не изучался неподготовленному кандидату.

Если кандидат сдает MCPD, это необязательно означает, что он сможет сдать любой MCTS из соответствующего пути на этот MCPD. Это необходимо четко понимать.

 

Проблемы?

 

Следующие проблемы были замечены как у автора статьи, так и у многих людей, с которыми автор контактировал и пытался помочь в сдаче экзаменов.
1) Пост-регистрационная депрессия. Возникает обычно тогда, когда кандидат изначально поставил перед собой причину, по которой он хочет сдать экзамен, которая не соответствует действительно либо является выдуманной. Например, “если я сдам этот экзамен, то обязательно буду принят на высокооплачиваемую работу в X”. Может, это и произойдет. Насколько же знаю я, на высокооплачиваемой работе на интервью проверяют реальные знания даже в случае наличия сертификатов, либо не проверяют знания совсем, основываясь на каких-либо других метриках. Сертификат иметь престижно, но когда удовлетворяется внутренний потребитель за счет знания того, что подтверждается некая установленная планка, поведение кандидата резко меняется. Проблема же заключается в том, что кандидат начинает думать, зачем ему в действительно нужен этот экзамен. Время же, которое тратится на приход к правильной причине, является достаточно бесполезным.
2) Большое количество пробелов в знаниях уже после регистрации на экзамен и, соответственно, “я никогда не сдам этот экзамен”.. Это абсолютно нормальная ситуация, в которой просто необходимо правильно построить путь закрытия этих пробелов. Кроме этого, у Microsoft существует специальная программа Second Shot (Второй Шанс), позволяющая сдать некоторые экзамены второй раз в том случае, если в первый этого сделать не получилось. Подробнее про периодически меняющиеся экзамены можно почитать на самом сайте Microsoft Learning по ссылке
http://www.microsoft.com/learning/ru/ru/2nd-shot.aspx .

3) Моя организация не хочет оплачивать покупку ваучера на экзамен. Если организация не хочет делать этого, то это не причина не сдавать интересующий экзамен. Самообразование – это то, что может и должен делать каждый человек, связанный с IT. Подготовка к одному экзамену предоставляет одно большое преимущество – вы в любом случае узнаете много нового в ее процессе. Что может быть ценнее этого?

4) Несдача экзамена. Это опять же абсолютно нормальная ситуация, которая означает лишь то, что необходимо отрегулировать уровень своей установленной планки, сдвинув ее, например, на более простой экзамен из того же трека либо просто взяв дополнительное время на подготовку. Необходимо понимать, что всего знать невозможно, и, даже если изучить всю найденную документацию, можно встретить в экзамене неожиданный вопрос, который может быть просто не понят из-за конструкций языка.

 

Пример?


Разумеется, без примера было бы можно назвать эту статью слишком философской. Я приведу пример своего плана, подготовленного для сдачи сертификационного экзамена 70-487 Developing Windows Azure and Web Services. Возможно, многого в этом плане не хватает, но отправной точкой к созданию собственного или расширению этого вполне может быть использован. Для собственного удобства я разбил его на определенные темы согласно странице экзамена на сайте Microsoft Learning – http://www.microsoft.com/learning/en/us/exam-70-487.aspx#fbid=KKy0fOW4PS2 .

Accessing Data (24%)

Обзор ADO.NET: ADO.NET Overview

Видео-курс SQL Server Fundamentals: http://pluralsight.com/training/courses/TableOfContents?courseName=sql-server-fundamentals&highlight=dan-sullivan_queryplanmgt*11#queryplanmgt

Обзор Entity Framework: Introducing Entity Framework

Обзор Entity Framework #2: Entity Framework Overview

Видео-курс Entity Framework and Data Models: http://pluralsight.com/training/courses/TableOfContents?courseName=efintro-models&highlight=julie-lerman_efintro-module1#efintro-module1

Обзор WCF Data Services: WCF Data Services 

Обзор WCF Data Services #2: WCF Data Services Overview

LINQ Fundamentals: http://pluralsight.com/training/courses/TableOfContents?courseName=linq-fundamentals&highlight=scott-allen_linq-introduction*14#linq-introduction

LINQ Data Access: http://pluralsight.com/training/courses/TableOfContents?courseName=linq-data-access&highlight=scott-allen_linq-dataservices!scott-allen_linq-entityframework-part2!scott-allen_linq-entityframework-part1*2#linq-dataservices

Entity Framework 4.0 by example: http://pluralsight.com/training/courses/TableOfContents?courseName=ef4-fundamentals&highlight=julie-lerman_ef4-using!julie-lerman_ef4-data-binding*1!julie-lerman_ef4-and-pocos!julie-lerman_ef4-models!julie-lerman_ef4-data-access!julie-lerman_ef4-t4-templates#ef4-using

Windows Azure Caching Service: http://pluralsight.com/training/courses/TableOfContents?courseName=azure-caching&highlight=scott-seely_azure-caching-m1*3,5!scott-seely_azure-caching-m2-dev*0,7,1,2,3,4,5,6!scott-seely_azure-caching-m3-other*0,5,1,3,2,4#azure-caching-m1

Windows Azure: The big picture: http://pluralsight.com/training/courses/TableOfContents?courseName=azure-bigpicture&highlight=david-chappell_azure-bigpicture-m1-survey*7#azure-bigpicture-m1-survey

Windows Server AppFabric Cache: http://pluralsight.com/training/courses/TableOfContents?courseName=appfabriccache&highlight=jon-flanders_appfabriccache-m1-introduction*1#appfabriccache-m1-introduction

Web Performance: http://pluralsight.com/training/courses/TableOfContents?courseName=web-performance&highlight=robert-boedigheimer_miscellaneous-performance*1,2#miscellaneous-performance

API: SqlCacheDependency ClassSqlCacheDependencyAdmin Class, System.Transactions, TransactionScope Class, IsolationLevel Enumeration

Distributed Transactions

Видео-курс Entity Framework and Data Models: http://pluralsight.com/training/courses/TableOfContents?courseName=efintro-models&highlight=julie-lerman_efintro-module1#efintro-module1

Обзор WCF Data Services: WCF Data Services 

Обзор WCF Data Services #2: WCF Data Services Overview

Building an OData Service (Part I)
Consuming OData using .NET
Consuming OData using jQuery

API: XmlNode Class (System.Xml) , XmlDocument Class , XmlWriter Class (System.Xml), XmlReader Class (System.Xml), XmlDocument Class, XmlNode Class (System.Xml), XPathNavigator Class (System.Xml.XPath)

LINQ to XML
Introduction to XML and XSLT in C#.Net – CodeProject

 

 

Implement data storage in Windows Azure

SQL Azure http://pluralsight.com/training/courses/TableOfContents?courseName=azure-sql-course&highlight=

Azure Cloud Services Storage Fundamentals http://pluralsight.com/training/courses/TableOfContents?courseName=azure-cloud-services-storage-fundamentals&highlight=

Windows Azure Building Blocks. Сервис Caching.

Пояснения по нововведениям в Windows Azure: сервисы хранилища. Ч.4

Пояснения по нововведениям в Windows Azure: сервисы хранилища. Ч.3.

Пояснения по нововведениям в Windows Azure: сервисы хранилища. Ч.2.

Пояснения по нововведениям в Windows Azure: сервисы хранилища.

Различия между локальным эмулятором хранилища и сервисами хранилища Windows Azure

Основы хранилища Windows Azure. Партиции.

Основы хранилища Windows Azure. Очереди.

Основы хранилища Windows Azure. Таблицы.

Основы хранилища Windows Azure. Блобы.

Сервисы хранилища Windows Azure. Рассуждения о простом усеченном экспоненциальном алгоритме отката для очередей.

Data Storage Offerings on the Windows Azure Platform

Using Windows Azure CDN – .NET – Develop
Retry Logic for Transient Failures in Windows Azure SQL Database

SQL Azure Retry Logic sample in C# for Visual Studio 2010

 

Querying and Manipulating Data by Using the Entity Framework (20%)

LINQ and Deferred Execution

Lazy Loading,Eager Loading,Explicit Loading in Entity Framework
How to use Transaction in Entity FrameWork?

SaveChanges Method

Обзор Linq To Entities: http://msdn.microsoft.com/ru-ru/library/bb386964(v=vs.90).aspx

Обзор Linq To Entities #2: http://professorweb.ru/my/LINQ/linq_entities/level14/14_3.php

API: System.Data.SqlClient Namespace
Async in Entity Framework 6.0

 

Designing and Implementing WCF Services (19%)

 

Все темы из этой секции обсуждаются в ссылках выше. +

1. Что нового в WCF 4.5? Начнём с конфигурации WCF

2. Что нового в WCF 4.5? Один WSDL-файл.

3. Что нового в WCF 4.5? Подсказки конфигурации и intellisense в файлах конфигурации

4. Что нового в WCF 4.5? Проверки конфигурации

5. Что нового в WCF 4.5? Поддержка множественной аутентификации на одну точку входа в IIS

6. Что нового в WCF 4.5? Точка входа HTTPS для IIS

7. Что нового в WCF 4.5? BasicHttpsBinding

8. Что нового в WCF 4.5? Изменения в режиме совместимости ASP.NET

9. Что нового в WCF 4.5? Улучшенный стриминг в IIS

Creating and Consuming Web API-based services (18%)

Web API и Windows Azure. Часть 1. История, немного про REST, примеры.

Basic Authentication with Asp.Net WebAPI

Implementing [RequireHttps] with ASP.NET Web API

AuthorizeAttribute Class

Coding Horror: Cross-Site Request Forgeries and You

Custom Action Filter in ASP.Net MVC application

 

 

Deploying Web Applications and Services (19%)

Update, Upgrade and VIP-Swap for Windows Azure Service–What are the Differences?

Overview of Updating a Windows Azure Service
IIS for Developers: http://pluralsight.com/training/courses/TableOfContents?courseName=iis-for-developers&highlight=steve-evans_iis-manage*3#iis-manage

http://pluralsight.com/training/Courses/TableOfContents/azure-websites

Web.config transformations: http://msdn.microsoft.com/en-us/library/dd465318(v=vs.100).aspx

Для того, чтобы познакомиться с мнением человека, отвечающего за Microsoft Learning, можно изучить следующие ссылки:

· «Что ждет ИТ-специалистов в облачную эпоху», «Подумайте об актуальности своих знаний», «В ИТ найдется место и молодым, и ветеранам»

· «Начинать надо с актуализации знаний»

· «Инициатива по своему обучению должна идти от сотрудника»

· «Лютц Зиоб: Уровень безработицы для специалистов, которые имеют адекватные знания в сфере ИТ, равен нулю»

May 28, 2013 / ahriman hpc mode

Ошибка ‘DevelopmentStorageDb201210′ already exists. Choose a different database name.. при запуске эмулятора хранилища Windows Azure

Здесь все очень просто. Эта ошибка может возникать даже при чистом развертывании девелоперской машины. Если вы не использовали собственноручно ранее LocalDb, который используется по умолчанию, то достаточно выполнить в командной строке две команды:

sqllocaldb stop "v11.0"

sqllocaldb delete "v11.0"

И все заработает. Таким образом мы останавливаем LocalDb и удаляем существующий экземпляр.

May 9, 2013 / ahriman hpc mode

Web API и Windows Azure. Часть 1. История, немного про REST, примеры.

Привет.

Начинаю новый цикл статей, на этот раз о Web API и приложении этого дела к Windows Azure. Статей будет неизвестно сколько, может, две, может десять, поэтому по мере наполнения буду добавлять всё в оглавление и потом, как обычно, причешу и соберу в PDF.

В этой части:

* История

* Зачем нужен Web API, если есть WCF, например

* Концепции REST и модель RMM

* Пример первого приложения ASP.NET MVC + Web API + jQuery + AJAX

* Использование OData в Web API

Итак, для того, чтобы понять, зачем всё это нужно, необходимо определиться с объектом изучения и его предназначением. Но сначала немного истории, чтобы было понятнее, почему (по моему мнению) была введена новая сущность в лице Web API.

История

       Не углубляясь в подробности того, как было, достаточно сообщить, что Microsoft прошла долгий путь в вопросах разработки сервисоориентированных систем, который оброс несколькими основными столпами: ASMX, .NET Remoting, WCF. Используя веб-сервисы на основе ASMX (это ~2002 год), разработчики могли довольно просто создать веб-сервис, который реализовывал различные версии SOAP, но был доступен только поверх HTTP. Параллельно существовала технология Remoting, которая давала возможность разрабатывать сервисы, которые могли использовать не только HTTP. В 2006 году Microsoft выпустила .NET 3.0 и Windows Communication Foundation (WCF), которая разом покрывала то, что предлагали ASMX и .NET Remoting, и предлагала еще больше новых возможностей, включая поддержку новых стандартов. Например, с WCF можно разработать веб-сервис для TCP, с поддержкой аутентификации по токенам безопасности, и запустить его в собственноручно разработанном сервисе Windows. Лично мое знакомство с WCF началось в 2009 году, когда я написал небольшую оснастку для сбора логов с двух десятков машин в кластере – на головной машине был запущен WCF-сервис, остальные же машины выполняли раз в N минут скрипт на Powershell, который вызывал WCF-сервис и передавал ему данные. Не скажу, что это было совсем просто делать с первого раза, но сама элегантность подхода мне очень понравилась.

    В 2007 году в версии CTP был выпущен фреймворк ASP.NET MVC. Уже тогда витала идея о том, что Интернет используется довольно просто – для обмена информацией между веб-страницами используются чаще всего текстовые сообщения, а не бинарные данные, используется HTTP, клиентская часть для обработки различных задач. Это привело к идее разработки того, что имело бы поддержку сериализации только в XML и JSON. Зачем, собственно, мне, если я хочу создать простейший RESTful сервис, использовать в целом местами тяжеловесный WCF, который, тем более, не особо ложился на REST?  Вот тут и вступил в игру ASP.NET MVC со своим встроенным механизмом маршрутизации.

Маршрутизация MVC

В отличие от WCF, где сервис = адрес физического файла, механизм маршрутизации в MVC работает по иному принципу – он ассоциирует адрес с методом контроллера.

Если рассматривать пример, то, если бы имели сервис WCF, то обращение к нему происходило бы так:

http://server/MyService.svc

Если ASP.NET MVC, то так:

http://server/MyService/Get/123

Как видите, подобная адресация позволяет скрыть детали внутренней реализации. С помощью маршрутизации MVC мы можем перевести запрос по вышеупомянутому адресу на любой метод любого контроллера. Все это приводит к гораздо более простой поддержке приложения – мы можем менять внутреннюю реализацию так, как представляется удобным, и, например, быстро менять старую версию реализации на новую, всего лишь подправив конфигурацию маршрутизации. Создание же Web API (в общем-то, "нашлепка" на ASP.NET) позволило разрабатывать с использованием этого механизма маршрутизации HTTP REST-сервисы, которые работают в одном проекте с ASP.NET MVC и, в общем-то, полностью интегрируются в контекст (не имплементации, а логический) MVC. Но, перед тем, как начать писать REST-сервис с Web API, нужно определиться с тем, что я называю REST-сервисом. Об этом – ниже.

Немного про REST

Многие думают, что если сделать линки красивыми, то их API уже будет 100% REST. На самом деле это, конечно же, не так, и REST, упомянутый впервые в диссертации одного умнейшего человека, не так прост, как кажется. Правила построения REST-сервисов диктуют также и ограничения, которые накладываются далее на архитектуру, и это надо учитывать и соглашаться (или не соглашаться).

Для того, чтобы понять, что под собой подразумевает путь к REST, можно воспользоваться моделью RMM (REST Maturity Model), представленной Леонардом Ричардсоном в 2008 году. Те, кто знаком с CMMI (Capability Maturity Model Integration), сразу увидят сходство в словах – оно неслучайно. Эта модель, как и CMMI, описывает несколько уровней соответствия некоторому своду правилу, методологии. RMM содержит 4 уровня –  от 0 до 3. В этой модели все начинается с самого простого на уровне 0, когда API соответствует стилю RPC, и заканчивается удовлетворяющим всем основным парадигмам REST. Разумеется, что, если использовать эту модель для описывания собственной системы, если засели на каком-то уровне, меньшем последнего – этот сервис не REST. Давайте сначала посмотрим на не очень красивую картинку, схематично изображающую RMM, после чего перейдем к примеру и разберем его согласно всем уровням RMM. Примером нам будет служить сервис гостевой книги.

image

Уровень 0

Согласно уровню 0, у нас был бы простой WCF-сервис GuestService, у которого был бы один метод CreatePost(), который принимал бы аргументы заголовка записи, имени пользователя и его e-mail. В ответ метод возвращал бы номер записи. Специально для администратора было бы еще несколько методов – DeletePost() и UpdatePost(). Каждый из них принимал бы какое-то сообщение и возвращал какой-то ответ. И, конечно же, GetAllPosts(). Обычная система, ничего примечательного.

Таким образом, наш сервис на уровне 0 RMM выглядел бы так:

Метод URL HTTP-метод Видимость
CreatePost /api/GuestService.svc POST Например, WSDL
DeletePost /api/GuestService.svc POST Например, WSDL
UpdatePost /api/GuestService.svc POST Например, WSDL
GetAllPosts /api/GuestService.svc POST Например, WSDL

Согласно таблице, у нас есть некоторое API, каждая из операций которого имеет одну и ту же ссылку (URL). В целом же ссылка выглядит совершенно непонятно и непривязано к контексту – удаляем мы запись с номером 1, или обновляем пост с номером 100 – URL будет тот же самый. Эта система удовлетворяет уровню 0 RMM и основным характеристикам – один URL = один HTTP-метод. Если смотреть на HTTP-методы, то тут все тоже одинаково – везде POST, да еще и методы самому приходится внутри создавать. Одно из правил RESTful HTTP – не надо создавать самому какие-то методы. Надо соответствовать тому списку, который содержит доступные HTTP verbs. Но об этом чуть позже.

Да, и, конечно, в нашей ситуации с данным сервисом клиент должен каким-то образом знать о том, как вызвать то или иное действие, то есть должна наличествовать определенная связь, например, клиент должен знать о контрактах (вот он, WSDL). Это тоже нехорошо – лишние связи – зачем они нам? Тем более что REST гласит, что нужно знать только основной адрес, все остальные операции должны быть доступны через так называемые гипермедиа-элементы (ссылки, формы, элементы управления). Сервер должен управлять всем процессом – диктовать то, как должны выглядеть ссылки, формы, забирая эти знания на себя и не делясь им с клиентом, чтобы, если что-то изменилось, быстро отреагировать на эти изменения. Это все – компоненты и части принципа HATEOAS, о котором позже. Пока же перейдем на уровень 1.

Уровень 1

Итак, мы захотели превратить наш сервис в REST-сервис. Что же мы должны сделать? Во-первых, удовлетворить правилам уровня 1. Правила уровня 1 гласят, что REST-сервис должен быть ресурсоориентированным, то есть ориентироваться не на запрос-ответ и методы, как в RPC, а на ресурсы, ограничиваемые набором HTTP verbs. И всё. Есть набор доступных HTTP verbs – больше ничего не надо. GET, DELETE, POST, иногда PUT и еще более иногда HEAD и иже с ними. Этот принцип основополагающ для REST-сервисов – если у нас сервис предлагает большую пачку различных методов, он не будет REST (согласно RMM).

Таким образом, следуя правилу уровня 1 “Много URL, один HTTP метод”, построим новую табличку для API.

Метод URL HTTP-метод Видимость
CreatePost /api/posts POST Например, WSDL
DeletePost /api/posts/1 POST Например, WSDL
UpdatePost /api/posts/1 POST Например, WSDL
GetAllPosts /api/posts POST Например, WSDL

Но и тут образовывается проблема RESTful-ности – клиент продолжает не представлять о том, чем отличаются ссылки /api/posts и /api/posts – без контракта и, например, WSDL. Клиент должен иметь контракт. Связность продолжает наблюдаться, и, кроме этого, продолжает наблюдаться один HTTP-метод. Но, по крайней мере, наш сервис перебрался на 1 уровень модели RMM. Попробуем перейти на 2.

Уровень 2

Правило уровня 2 = “Много URL = Много HTTP-методов”. Здесь в полной мере надо переосмыслить свой сервис в сторону ресурсоориентированности. Что приходит от клиента? Как это обрабатывать? Куда посылать?

По факту, конечно, нет такого HTTP-метода, как CreatePost, и GetAllPosts тоже нет.  Но есть POST и GET! И PUT и DELETE тоже. Мы можем ассоциировать наши методы, возможно, кое-что переименовав, и перейти на уровень 2. Здесь нужно уточнить, что HTTP-методы имеют некоторые особенности, например, PUT и DELETE идемпотентны. Это значит, что сколько бы мы не вызвали эти методы, они возвратят один и тот же результат- HTTP-ответ – например, сколько бы мы не вызывали PUT, будет изменяться одна и та же сущность. POST же не идемпотентен по понятной причине – создается новая сущность. GET не идемпотентен, но безопасен – в системе ничего не меняется и не должно меняться при любом количестве вызовов GET. Это очень важно, так как я встречал одну систему, в которой в методе GET на стороне сервера происходила логика изменения состояния сущностей в источнике данных. Это неправильно.

Посмотрим теперь, что произошло с нашим сервисом на уровне 2.

Метод URL HTTP-метод Видимость
CreatePost /api/posts POST Например, WSDL
DeletePost /api/posts/1 DELETE Например, WSDL
UpdatePost /api/posts/1 PUT Например, WSDL
GetPost /api/posts GET Например, WSDL

Уже лучше. Теперь у нас сервис, который имеет набор соответствующих HTTP-методов и различные URL (по большей части). Но мы всё ещё связаны с клиентом. Чтобы решить это, пойдем на уровень 3.

Уровень 3

Уровень 3 характеризуется одной емкой аббревиатурой – HATEOAS. Посыл этой аббревиатуры заключается в том, что клиент не должен знать ничего, кроме начального адреса сайта. Все остальное ему подскажет сам сайт – с помощью ссылок, кнопок, элементов управления. Клиент должен получать доступ к ресурсам и их управлению без предварительных знаний о том, как это сделать.

Нарушить связность можно, предоставив возможность клиенту менять состояние, используя то, что возвращает сервис – например, если клиент перешел на определенный адрес, ему может быть возвращены соответствующие данные. В любом случае, создатель сервиса должен быть уверен, что при нажатии на кнопку Submit веб-формы будет инициирован POST-запрос и вызван соответствующий метод.

Итак, удовлетворяющее 3 уровню API приведено в таблице. Хотелось бы обратить внимание, что, несмотря на всё это, даже если сервис удовлетворяет всем условиям RMM, могут быть определенные нюансы, которые нарушат всё.

Метод URL HTTP-метод Видимость
CreatePost /api/posts POST HTTP POST
DeletePost /api/posts/1 DELETE HTTP DELETE
UpdatePost /api/posts/1 PUT HTTP PUT
GetPost /api/posts GET HTTP GET

И последнее про REST

И последнее про REST – если удовлетворять стандартам, образовавшимся вокруг HTTP, то нельзя забывать про коды HTTP. Сервис должен возвращать известные коды ошибок. Это необязательное условие, но, если эти коды есть, значит, их придумали и утвердили умные люди, и желательно использовать их, чтобы тот, кто будет поддерживать сервис, не увидел ничего, что нарушило бы его уверенность в том, что автор сервиса писал код в сознательном состоянии.

Ниже приведена таблица с извесными кодами HTTP.

Код статуса Значение
200 ОК, запрос выполнен успешно.
201 Запись создана – может включать ссылку на созданный ресурс
202 То же самое, что и 200, но используется в связке с асинхронной операцией.
301 Запрашиваемый ресурс был перемещен – нужно включать в сообщение URL на новое расположение ресурса
400 Плохо оформленный запрос.
401 Unauthorized – клиенту не разрешен доступ к ресурсу.
403 Доступ запрещен – клиент аутентифицировался, но не прошел авторизацию.
404 Ресурс не найден либо клиент не имеет доступа и не должен знать, почему.
409 Конфликт на сервере – используется в ответ на PUT, когда несколько клиентов используют один ресурс.
500 Ошибка на сервере.

Web API

Напомню, что Web API появился в ASP.NET MVC 4 и сразу же вызвал достаточно много разговоров о себе. Очередная технология для помощи в создании веб-сервисов, опять REST, зачем нам это нужно? Это хороший вопрос – ведь есть всякие WCF и иже с ним.  Но всё это вещи, если можно так выразиться, глобальные, и, когда нужно реализовывать какой-то небольшой сценарий, то надо тянуть за собой еще немного того, что не нужно и неизвестно, пригодится ли. Web API – это как раз то средство, которое позволяет очень просто, быстро и красиво реализовать сценарий RESTful-сервиса с использованием HTTP.

Создадим ASP.NET MVC 4 приложение и выберем соответствующий Web API шаблон.

image

image

После того, как проект будет создан, вы увидите обыкновенное MVC-приложение. Первой точкой входа будет новый контроллер – ValuesController, который является специализированным контроллером WebAPI и наследуется, в свою очередь, не от Controller, а от ApiController.

Как и в любом другом контроллере, scaffolding уже создает некоторый код, в случае Web API-контроллера это "болванки" для методов, замыкающих на себя HTTP verbs – GET, POST, PUT и DELETE.

HTTP Verb Метод контроллера Описание
Get() GET Метод возвращает набор данных в виде массива. Может быть возвращен любой тип коллекции IEnumerable.
Get(string) GET Метод возвращает одну сущность, которая связана с тем, что передается в виде string (часто это ID).
Post(string) POST Метод добавляет новую сущность в систему.
Put(string,string) PUT Метод обновляет существующую сущность. Различие между Put и Post состоит в том, что Post всегда создает новую сущность, Put – нет.
Delete(string) DELETE Метод удаляет сущность из системы.

Теперь добавим контекст для тестовой базы данных. В данном цикле статей я буду использовать тестовую базу данных, которую всегда использую, когда веду курсы в http://atraining.ru. Она состоит всего из двух очень простых несвязанных таблиц – CourseSet и Student. В дальнейшем, может, и усложнится, но это непринципиально для обсуждаемой темы.

image

 

Внесем изменения в контроллер WebAPI, определив соответствующим образом поведение его методов. Так как код очень простой и понятный, приведу его без комментариев.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Web.Http;
using WebApiJsonAjax.Models;
namespace WebApiJsonAjax.Controllers
{
    public class ValuesController : ApiController
    {
        private atrainingdatabaseEntities _ctx = new atrainingdatabaseEntities();
        // GET api/values
        public List<Models.Student> Get()
        { 
            
              var students = from e in _ctx.Student select e;
              return students.ToList(); 
     
             
        }

       
        // GET api/values/5
        public string Get(int id)
        {
            return "value" + id;
        }

        public Student Post(Student student)
        {
            return student;
        }

        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        { 
            var student = _ctx.Student.Where(s => s.id == id).FirstOrDefault();
_ctx.Student.Remove(student);
_ctx.SaveChanges(); 
            
        }
    }
}

Обращу внимание, что я не просто так где-то использую нотацию LINQ в виде расширений и лямбд, а где-то – в ином виде. Просто чтобы запомнить. На самом деле мне кажется, что нотация LINQ в виде расширений гораздо более понятна, несмотря на активное использование лямбд, но – на вкус и цвет.

Сохраним контроллер и попробуем протестировать то, что получилось. Нажмем F5 и перейдите на ссылку http://localhost:[port]/api/values . Обратим внимание, что при обращении с GET-запросом к этой ссылке будет выдан результат в виде JSON. WebAPI умеет работать и возвращать значения в виде JSON и XML, это зависит от того, что клиент понимает. Посмотрим, что он возвратит в Chrome и IE (скриншоты расположены соответственно), чтобы подойти к еще одной замечательной особенности Web API под названием Content Negotiation.

image

image

Весь процесс сериализации в JSON объекта типа Student взял на себя фреймворк, что не может не радовать – в отличие, например, от использования ASP.NET MVC, когда для того, чтобы возвратить JSON из контроллера, нужно использовать return Json явным образом. Давайте рассмотрим, почему же в двух браузерах сервис возвратил результат в разных форматах.

Content Negotiation

В стандарте HTTP есть такое понятие, как Content Negotiation, которое означает процесс согласования между клиентом и сервером деталей относительно их коммуникаций. Когда клиент обращается к серверу, он отправляет в запросе директиву Accept, в которой пишет, что и в какой мере он ожидает увидеть от сервера в ответе. Попробуем выполнить тот же самый запрос GET, но с помощью утилиты curl – с ее помощью можно довольно просто отслеживать, что происходит во время запроса. Дополнительно будут скриншоты из Fiddler. Также посмотрим запросы, которые отправляются Chrome и IE, с помощью интегрированных в сами браузеры средств.

image

 

image

 

Интерфейс Fiddler, с которым мы будем также работать параллельно curl.

image

 

Значение Accept – это то, что хотел бы увидеть клиент от сервера. Как видно из скриншотов, Chrome хочет видеть text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 (q – это “вес” формата, чем больше вес, тем больше “хочет” клиент увидеть результат именно в этом формате и указывает на это серверу). IE же хочет видеть text/html, application/xhtml+xml, */*. Хочу обратить внимание, что Web API не распознает то, что хочет видеть IE, и отправляет результат по умолчанию в JSON – у него нет поддержки application/xhtml+xml, но есть поддержка */*, то есть “приму всё, что предложит сервер”. Chrome же получает то, что хочет, в желаемом формате XML.

Давайте теперь посмотрим, как можно это сделать в curl и Fiddler и имитировать некоторые аспекты поведения. Обратимся с запросом GET.

image

image

 

Ответ в JSON, так как клиенту все равно, в каком формате придет результат.

Давайте укажем явным образом, что мы хотим увидеть.

image

image

Замечательно – формат ответа зависит от того, чего хочет клиент.

Этот процесс и называется Content Negotiation, и он является очень важным процессом в коммуникациях между клиентом и сервером. Хочу также обратить внимание на то, с какой простотой и элегантностью решен выбор между форматами. Указание же формата результата на сервере сопряжено с несколько более сложным кодом, который приведен ниже.

public HttpResponseMessage Get()
{

    var students = (from e in _ctx.Student select e);

    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content = new ObjectContent<IEnumerable<Student>>(students, new JsonMediaTypeFormatter());

    resp.Headers.ConnectionClose = true;
    resp.Headers.CacheControl = new CacheControlHeaderValue();
    resp.Headers.CacheControl.Public = true;

    return resp;

}

Если вы хотите возвратить результат именно в том формате, в котором хотите _вы_, не учитывая клиента, то необходимо получить доступ к сообщению, которое будет формироваться для результата, и определить его свойства, передав его специальному механизму – Formatter. Конечно же, вы можете писать свои конвертеры со сколь угодно сложной логикой.

Итак, в коде выше происходит:

1) Получаются данные из коллекции Student

2) Создается экземпляр класса HttpResponseMessage со статусом 201 OK. Это сообщение будет возвращено клиенту.

3) В содержание сообщения вкладывается наша модель данных, которая конвертируется в формат JSON.

4) Сообщение возвращается клиенту.

Давайте повторим наш запрос в curl, указав, что мы хотим видеть только application/xml.

image

Несмотря на Accept: application/xml, результат был возвращен в формате JSON.

Content Negotiation в Web API во всей своей красоте. А мы двигаемся дальше.

Использование Web API из представления MVC с помощью jQuery

У нас уже есть почти готовый REST-сервис. Но в Web API вполне закономерно не предусмотрен механизм генерации представлений. Свяжем сервис с представлением MVC.

Использовать Web API мы будем из представления Index у HomeController. С помощью jQuery заберем данные из сервиса и нарисуем простую табличку.

Привожу весь код страницы.

<header>
    <div class="content-wrapper">
        <div class="float-left">
            <p class="site-title">
                <a href="~/">ASP.NET Web API</a></p>
        </div>
    </div>
</header>
<div id="body">
    <section class="featured">
        <div class="content-wrapper">
           
            <table id="students"></table>
            <script>
               
                $(function () {
                    var $students = $("#students");
                    $.ajax({
                        url: "api/values",
                        contentType: "json",
                        success: function(data) {
                            $.each(data, function(index, item) {
        var $row = $("#templates").find(".row-template").clone();
        $row.find(".Name").html(item.name);
        $row.find(".delete").click(function() {

        $.ajax({ url: "api/values/" + item.id,
                                        type: "DELETE",
                                        success: function() {
                                            $row.remove();
                                        }
                                    });

                                });
                                $students.append($row);
                               
                            });
                        }
                    });
                })

            </script>
        </div>
    </section>
    <section class="content-wrapper main-content clear-fix">
       
        <div id="templates" style="display:none">
           
            <table>
               
                <tr class="row-template">
                   
                    <td class="Name"></td>
                    <td><input type="button" value ="Del" class="delete"/></td>

                </tr>

            </table>

        </div>

    </section>
</div>

Код достаточно прост – мы получаем из сервиса данные и динамически заполняем таблицу. Ниже приведен скриншот текущего представления

image

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

image

Добавим остальную функциональность – PUT и POST. Для этого надо написать достаточно много кода. Приведу полные листинги представления и контроллера с выделенными красным участками измененного кода.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Web.Http;
using WebApiJsonAjax.Models;
namespace WebApiJsonAjax.Controllers
{
    public class ValuesController : ApiController
    {
        private atrainingdatabaseEntities _ctx = new atrainingdatabaseEntities();

        public HttpResponseMessage Get()
        {

            var students = (from e in _ctx.Student select e);

            var resp = new HttpResponseMessage(HttpStatusCode.OK);
            resp.Content = new ObjectContent<IEnumerable<Student>>(students, new JsonMediaTypeFormatter());

            resp.Headers.ConnectionClose = true;
            resp.Headers.CacheControl = new CacheControlHeaderValue();
            resp.Headers.CacheControl.Public = true;

            return resp;

        }

        // GET api/values/5
        public string Get(int id)
        {
            return "value" + id;
        }

        public HttpResponseMessage Post([FromBody]Student student)
        {
            try
            {
                _ctx.Student.Add(student);
                _ctx.SaveChanges();
            }
            catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message);

            };
            return Request.CreateResponse(HttpStatusCode.OK);
        }

        // PUT api/values/5
        public HttpResponseMessage Put(int id, Student student)
        {
            try
            {
                var studentToChange = _ctx.Student.FirstOrDefault(s => s.id == id);
                studentToChange.name = student.name;
                _ctx.SaveChanges();
            } catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message);

            };
            return Request.CreateResponse(HttpStatusCode.OK);
        }

        // DELETE api/values/5
        public void Delete(int id)
        { 
            
                var student = _ctx.Student.Where(s => s.id == id).FirstOrDefault();
                _ctx.Student.Remove(student);
                _ctx.SaveChanges(); 
            
        }
    }
}

В контроллере появилась реализация методов PUT и POST. В обоих методах операции завернуты в блок try/catch и, если что-то не получается, создается ответ, в который вкладывается сообщение об ошибке. Здесь нужно еще упомянуть дополнительный атрибут, который может изрядно помочь в работе – вы можете пометить аргумент метода контроллера как [FromBody] либо [FromUrl], что означает, соответственно, брать значение этого аргумента из тела запроса и из URL.

Код представления ниже. В него добавлены обработчики событий нажатия на кнопки изменения и создания записей. Хочу обратить внимание на использование JSON.stringify – эта функция конвертирует предложенное ей в JSON.

<header>
    <div class="content-wrapper">
        <div class="float-left">
            <p class="site-title">
                <a href="~/">ASP.NET Web API</a></p>
        </div>
    </div>
</header>
<div id="body">
    <section class="featured">
        <div class="content-wrapper">
           
            <table id="students"></table>
            <script>

                $(function() {
                    var $students = $("#students");
                    $.ajax({
                        url: "api/values",
                        contentType: "json",
                        success: function(data) {
                            $.each(data, function(index, item) {
                                var $row = $("#templates").find(".row-template").clone();
                                $row.find(".Name").html("<input type=’text’ class=’studentname’ id=’" + item.id + "’ value=’" + item.name + "’></input>");
                                $row.find(".delete").click(function() {

                                    $.ajax({
                                        url: "api/values/" + item.id,
                                        type: "DELETE",
                                        success: function() {
                                            $row.remove();
                                        }
                                    });

                                });

                                $row.find(".change").click(function() {
                                    var student = {
                                        id: item.id,
                                        name: $row.find(".studentname").attr("value")
                                    };

                                    $.ajax({
                                        url: "api/values/" + item.id,
                                        type: "PUT",
                                        contentType: "application/json; charset=utf-8",
                                        data: JSON.stringify(student),
                                        success: function() {

                                        }
                                    });

                                });

                                $students.append($row);

                            });
                        }
                    });
                });

               function addStudent() {                   
                   

                    var student = {
                       name: $("#frm").find("#name").attr("value"),
                    };
                   $.ajax({
                        url: "api/values",
                        type: "POST",
                        contentType: "application/json; charset=utf-8",
                        data: JSON.stringify(student),
                        success: function() {
                            alert("Added!");
                        }
                    });

                }
            </script>
        </div>
    </section>
    <section class="content-wrapper main-content clear-fix">
       
        <div id="templates" style="display:none">
           
            <table>
               
                <tr class="row-template">
                    <form>
                    <td class="Name"></td>
                  
<td><input type="button" value ="Change" class="change"/></td>
                    <td><input type="button" value ="Del" class="delete"/></td>
                    </form>
                </tr>
                 
            </table>
       
        </div>
             <form id="frm">
                    <input type="text" name="name" id="name"/>
                    <td><input type="button" value ="Add" onclick="return addStudent();"/></td>
                   
                    </form>

    </section>
</div>

Сымитируем поведение операций создания, обновления и удаления с помощью curl и Fiddler. Обратите внимание, что в curl тело сообщения задается особым образом – если у нас сложная модель, то вводится name=Sychev, например, если какое-то одиночное значение, то необходимо, чтобы тело выглядело как -d "=Sychev".

POST:

image

image

 

PUT:

image

image

DELETE:

image

 

image

 

А вот, что бывает, если возвращать клиенту в ответе сообщение при ошибке.

 

image

Все, у нас готов REST-сервис на Web API с использованием ASP.NET MVC и jQuery. Теперь рассмотрим интересную дополнительную функциональность.

Поддержка OData в Web API

ASP.NET Web API имеет встроенную поддержку для некоторых параметров запросов OData, например, сортировки, фильтрации и разбиения на подмножества (paging).

Для того, чтобы начать использовать OData в Web API, необходимо установить соответствующий пакет с помощью NuGet. Вместе с пакетом OData установится пачка зависимостей.

image

 

Заменим метод Get на следующий код.

[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
      public IQueryable<Student> Get()
      {
          return _ctx.Student.AsQueryable();
      }

Для использования метода в OData нужно пометить его как [Queryable] и указать, что он должен возвращать IQueryable. Сериализовать данные OData будет несколько иным образом, каким – мы посмотрим чуть ниже.

Теперь добавим в файл WebApiConfig в папке App_Start несколько вкусностей, которые попробуем опять же чуть ниже. Код WebApiConfig должен выглядеть как код ниже.

 

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
       
GlobalConfiguration.Configuration.Formatters.JsonFormatter.AddQueryStringMapping("$format", "json", "application/json");
        GlobalConfiguration.Configuration.Formatters.XmlFormatter.AddQueryStringMapping("$format", "xml", "application/xml");

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }

Запустим проект и перейдем по ссылке http://localhost:[port]/api/values. Будет выведен XML, возвращаемый методом по OData.

image

Обратите внимание, что данные сериализуются несколько по-иному. Это нужно учитывать при разработке.

Теперь можно воспользоваться возможностями OData. Например, перейти по такой ссылке:

http://localhost:61020/api/values?$filter=(id eq 6)

Или по такой:

http://localhost:61020/api/values?$filter=(id eq 6)&$format=json

Format – нестандартная процедура, мы ее добавили дополнительно в файл WebApiConfig.

Используя OData, можно с помощью формирования ссылок в специальном легкоусвояемом расширяемом формате взаимодействовать с моделью данных, хранимой на сервере. Конечно же, нужно быть аккуратным, несмотря на то, что Web API OData предоставляет read only доступ к данным.

 

Спасибо за внимание.

 

 

April 29, 2013 / ahriman hpc mode

Использование Dynamic Data в Windows Azure и SQL Databases

Привет.

Несмотря на то, что многие адепты пишут, что фреймворк Dynamic Data можно использовать в широком спектре сценариев и этот спектр не ограничивается менеджментом данных и rapid-разработкой администраторской панели для этого самого менеджмента, я использую его именно для этой задачи. Ниже описана последовательность действий, которую я прошел для того, чтобы добавить в уже существующий проект Windows Azure веб-роль в виде Web Forms с Dynamic Data.

Итак, у нас уже есть существующий проект Cloud Services, который уже работает в production-ячейке. Для того, чтобы добавить в него новую веб-роль из существующего проекта, нельзя просто взять и сделать это. Сначала нужно добавить в solution новый проект, после чего в оснастке появится новая кнопка.

Создадим проект Dynamic Data. Версия .NET – 4.0. Можно использовать и новее, но конкретно в моем случае остальные проекты в solution используют именно 4.0, поэтому создавать зоопарк я не стал. Хотя хороший повод обновить весь solution Улыбка

image

Уходя немного в тему того, что такое DD и зачем он нужен – очень кратко: фреймворк DD, который можно беспроблемно запустить только в проекте ASP.NET Web Forms (в связи с некоторыми особенностями scaffolding) и довольно проблемно, но всё-таки запустить с MVC, это удобнейшее средство для построения портала менеджмента данных. Достаточно добавить в проект DD после его создания контекст данных EF или Linq-To-SQL, и определить, какие таблицы должны быть доступны для менеджмента, и DD после запуска самого проекта на выполнение будет в runtime создавать страницы этого менеджмента. То есть – запустили проект – появилась страница со списком доступных таблиц – страница сгенерировалась в runtime. Нажали на имя нужной таблицы, перешли на ее страницу – эта страница тоже до момента нажатия не существовала. Нажали на кнопку редактирования записи в этой таблице – перешли на автоматически созданную таблицу. При этом всё это счастье достаточно серьезно кастомизируемо, то есть все – дизайн, кнопки, страницы – можно переделать “под себя”. Единственная проблема – не совсем интуитивно понятно, как подмять этот проект под какую-нибудь аутентификацию, тот же самый Membership. Но об этом, может быть, в следующей статье.

Итак, создали проект. Добавим контекст данных Linq-To-SQL.

image

image

С помощью Server Explorer подключимся к базе данных и перекинем drag’n’drop таблицы из базы данных в дизайнер контекста. Хочу обратить внимание, что в данном случае мы используем базу данных, хранящуюся в SQL Azure Databases. Да, DD, несмотря на некоторые ограничения SQL Azure Databases, умеет использовать базу данных, хранящуюся в этом сервисе. И использовать базу данных SQL Azure Databases можно также, как любую другую базу данных SQL Server.

image

Теперь необходимо подключить контекст данных к фреймворку DD. Для этого в файле Global.asax.cs раскомментируем строку

DefaultModel.RegisterContext(typeof(YourDataContextType), new ContextConfiguration() { ScaffoldAllTables = false });

И поменяем значение ScaffoldAllTables на true – таким образом мы разрешим все таблицы, которые есть в контексте, к менеджменту с использованием портала DD. Здесь же можно указать таблицы выборочно либо добавить к scaffolding таблицы, которых нет в контексте, но это делается с использованием code first и добавления специальных атрибутов к таблице. Позже в runtime эти таблицы будут подключены к общему процессу выполнения.

Также поменяем значение YourDataContextType на имя контекста.

Итого:

DefaultModel.RegisterContext(typeof(DataClasses1DataContext), new ContextConfiguration() { ScaffoldAllTables = true});

Теперь давайте настроим проект для того, чтобы он мог бы быть добавлен как веб-роль к проекту Windows Azure Cloud Services. Для этого в файл проекта csproj добавьте в начало PropertyGroup элемент RoleType.

<PropertyGroup>
  <RoleType>Web</RoleType>

</PropertyGroup>

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

Теперь откроем наш solution Cloud Services и добавим созданный только что проект DD в облачный проект. Нажмем правой кнопкой мыши на ветке Roles, после чего выберем Web Role Project in Solution и выберем наш проект.

Всё готово. Теперь можно разворачивать проект.

 

April 12, 2013 / ahriman hpc mode

Установка collation для столбца в SQL Azure Database

Задача была простая – переустановить collation для столбца, хранящегося в таблице, хранящегося в базе данных, хранящейся в SQL Azure Databases. Так как я невеликий специалист в SQL Server, поиск решения занял минут N.

По умолчанию collation проставляются в SQL_Latin1_General_CP1_CI_AS, на сегодняшний момент управлять этим на уровне базы или сервера невозможно.

Поменять же collation на более низком уровне можно с помощью запроса

ALTER TABLE [dbo].[TableName] ALTER COLUMN [ColumnName]
            NVARCHAR(MAX) COLLATE Cyrillic_General_CI_AS NULL;
GO

Follow

Get every new post delivered to your Inbox.