Поделиться через


Создание конечной точки OData версии 3 с помощью веб-API 2

Майк Уосон

Скачивание завершенного проекта

Open Data Protocol (OData) — это протокол доступа к данным в Интернете. OData предоставляет единый способ структурирования данных, запроса данных и управления набором данных с помощью операций CRUD (создание, чтение, обновление и удаление). OData поддерживает форматы AtomPub (XML) и JSON. OData также определяет способ предоставления метаданных о данных. Клиенты могут использовать метаданные для обнаружения сведений о типе и связей для набора данных.

веб-API ASP.NET упрощает создание конечной точки OData для набора данных. Вы можете точно контролировать, какие операции OData поддерживает конечная точка. Вы можете разместить несколько конечных точек OData, а также конечные точки, отличные от OData. У вас есть полный контроль над моделью данных, внутренней бизнес-логикой и уровнем данных.

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

Поддержка OData веб-API была добавлена в ASP.NET and Web Tools обновлении 2012.2. Однако в этом руководстве используется формирование шаблонов, добавленных в Visual Studio 2013.

В этом руководстве вы создадите простую конечную точку OData, которую клиенты могут запрашивать. Вы также создадите клиент C# для конечной точки. После завершения работы с этим руководством в следующем наборе руководств показано, как добавить дополнительные функциональные возможности, включая связи сущностей, действия и $expand и $select.

Создание проекта Visual Studio

В этом руководстве вы создадите конечную точку OData, которая поддерживает базовые операции CRUD. Конечная точка будет предоставлять один ресурс— список продуктов. В последующих руководствах будут добавлены дополнительные функции.

Запустите Visual Studio и выберите Создать проект на начальной странице. Или в меню Файл выберите Создать , а затем Проект.

В области Шаблоны выберите Установленные шаблоны и разверните узел Visual C#. В разделе Visual C# выберите Интернет. Выберите шаблон веб-приложения ASP.NET .

Снимок экрана: окно нового проекта с путем к области шаблона и выделенными маршрутами для выбора параметра ВЕБ-приложение A P DOT NET.

В диалоговом окне Создать проект ASP.NET выберите пустой шаблон. В разделе "Добавление папок и основных ссылок для..." проверка веб-API. Нажмите кнопку ОК.

Снимок экрана: диалоговое окно проекта AS P DOT NET с полями параметров шаблона и выделенным параметром

Добавление модели сущностей

Модель — это объект, который представляет данные в приложении. Для работы с этим руководством нам нужна модель, представляющая продукт. Модель соответствует типу сущности OData.

В обозревателе решений щелкните правой кнопкой мыши папку Models. В контекстном меню выберите Добавить, а затем выберите Класс.

Снимок экрана: диалоговое окно обозревателя решений, в котором отображается список меню для каждого выделенного фрагмента, ведущий к параметру класса.

В диалоговом окне Добавление нового элемента назовите класс "Product".

Снимок экрана: окно

Примечание

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

В файле Product.cs добавьте следующее определение класса:

public class Product
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

Свойство ID будет ключом сущности. Клиенты могут запрашивать продукты по идентификатору. Это поле также будет первичным ключом в серверной базе данных.

Выполните сборку проекта. На следующем шаге мы будем использовать шаблон Visual Studio, который использует отражение для поиска типа Продукта.

Добавление контроллера OData

Контроллер — это класс, обрабатывающий HTTP-запросы. Вы определяете отдельный контроллер для каждого набора сущностей в службе OData. В этом руководстве мы создадим один контроллер.

В обозревателе решений щелкните правой кнопкой мыши папку Controllers. Щелкните Добавить, а затем выберите Контроллер.

Снимок экрана: окно обозревателя решений, в котором выделен параметр контроллера, который затем отображает меню для добавления контроллера o Data.

В диалоговом окне Добавление шаблона выберите "Веб-API 2 OData Controller with actions, using Entity Framework".

Снимок экрана: экран

В диалоговом окне Добавление контроллера назовите контроллер ProductsController. Установите флажок "Использовать действия асинхронного контроллера". В раскрывающемся списке Модель выберите класс Product.

Снимок экрана: диалоговое окно добавления контроллера с полями для имени контроллера, раскрывающегося списка класса модели и класса контекста данных.

Нажмите кнопку Новый контекст данных... . Оставьте имя по умолчанию для типа контекста данных и нажмите кнопку Добавить.

Снимок экрана: окно нового контекста данных с полем для нового типа контекста данных и именем по умолчанию для типа контекста данных.

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

Снимок экрана: диалоговое окно добавления контроллера с различными требованиями к полям с флажком

Примечание. Если появляется сообщение об ошибке "Произошла ошибка при получении типа...", убедитесь, что вы создали проект Visual Studio после добавления класса Product. Формирование шаблонов использует отражение для поиска класса .

Снимок экрана: Microsoft Visual Studio с красным кругом

Формирование шаблонов добавляет в проект два файла кода:

  • Products.cs определяет контроллер веб-API, реализующий конечную точку OData.
  • ProductServiceContext.cs предоставляет методы для запроса базовой базы данных с помощью Entity Framework.

Снимок экрана: окно проекта, в котором отображается меню службы продуктов и кружение двух добавленных файлов в контроллерах и в разделе моделей.

Добавление EDM и маршрута

В Обозреватель решений разверните папку App_Start и откройте файл с именем WebApiConfig.cs. Этот класс содержит код конфигурации для веб-API. Замените этот код следующим кодом.

using ProductService.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;

namespace ProductService
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Product>("Products");
            config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
        }
    }
}

Этот код выполняет две задачи:

  • Создает модель EDM для конечной точки OData.
  • Добавляет маршрут для конечной точки.

EDM — это абстрактная модель данных. EDM используется для создания документа метаданных и определения URI для службы. ODataConventionModelBuilder создает EDM с помощью набора стандартных соглашений об именовании EDM. Для этого подхода требуется минимальный код. Если требуется более полный контроль над EDM, можно использовать класс ODataModelBuilder для создания EDM путем явного добавления свойств, ключей и свойств навигации.

Метод EntitySet добавляет набор сущностей в EDM:

modelBuilder.EntitySet<Product>("Products");

Строка Products определяет имя набора сущностей. Имя контроллера должно совпадать с именем набора сущностей. В этом руководстве набор сущностей называется "Products", а контроллер — .ProductsController Если вы назвали набор сущностей "ProductSet", присвойте контроллеру ProductSetControllerимя . Обратите внимание, что конечная точка может иметь несколько наборов сущностей. Вызовите EntitySet<T> для каждого набора сущностей, а затем определите соответствующий контроллер.

Метод MapODataRoute добавляет маршрут для конечной точки OData.

config.Routes.MapODataRoute("ODataRoute", "odata", model);

Первый параметр — это понятное имя маршрута. Клиенты вашей службы не видят это имя. Второй параметр — префикс URI для конечной точки. Учитывая этот код, универсальный код ресурса (URI) для набора сущностей Products — http:// hostname/odata/Products. Приложение может иметь несколько конечных точек OData. Для каждой конечной точки вызовите MapODataRoute и укажите уникальное имя маршрута и уникальный префикс URI.

Начальное значение базы данных (необязательно)

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

В меню Сервис выберите Диспетчер пакетов NuGet, а затем консоль диспетчера пакетов. В окне "Консоль диспетчера пакетов" введите следующую команду:

Enable-Migrations

При этом будет добавлена папка с именем Migrations и файл кода с именем Configuration.cs.

Снимок экрана: меню службы продуктов обозревателя решений, кружающее только что добавленную папку с именем migrations и отображающее файл в ней.

Откройте этот файл и добавьте следующий код в Configuration.Seed метод .

protected override void Seed(ProductService.Models.ProductServiceContext context)
{
    // New code 
    context.Products.AddOrUpdate(new Product[] {
        new Product() { ID = 1, Name = "Hat", Price = 15, Category = "Apparel" },
        new Product() { ID = 2, Name = "Socks", Price = 5, Category = "Apparel" },
        new Product() { ID = 3, Name = "Scarf", Price = 12, Category = "Apparel" },
        new Product() { ID = 4, Name = "Yo-yo", Price = 4.95M, Category = "Toys" },
        new Product() { ID = 5, Name = "Puzzle", Price = 8, Category = "Toys" },
    });
}

В окне консоли диспетчера пакетов введите следующие команды:

Add-Migration Initial
Update-Database

Эти команды создают код, который создает базу данных, а затем выполняет этот код.

Изучение конечной точки OData

В этом разделе мы будем использовать прокси-сервер веб-отладки Fiddler для отправки запросов к конечной точке и изучения ответных сообщений. Это поможет вам понять возможности конечной точки OData.

В Visual Studio нажмите клавишу F5, чтобы начать отладку. По умолчанию Visual Studio открывает браузер в папке http://localhost:*port*, где port — это номер порта, настроенный в параметрах проекта.

Номер порта можно изменить в параметрах проекта. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите Свойства. В окне свойств выберите Интернет. Введите номер порта в поле Url-адрес проекта.

Сервисный документ

Сервисный документ содержит список наборов сущностей для конечной точки OData. Чтобы получить сервисный документ, отправьте запрос GET на корневой универсальный код ресурса (URI) службы.

С помощью Fiddler введите следующий универсальный код ресурса (URI) на вкладке Composer : http://localhost:port/odata/, где port — это номер порта.

Снимок экрана: окно сервисного документа с различными вкладками с выбранной вкладкой

Нажмите кнопку Выполнить . Fiddler отправляет приложению HTTP-запрос GET. Вы должны увидеть ответ в списке веб-сеансов. Если все работает, код состояния будет равен 200.

Снимок экрана: список веб-сеансов, показывающий протокол H T TP с результирующим номером 200, адресом ИП и узлом.

Дважды щелкните ответ в списке Веб-сеансы, чтобы просмотреть сведения об ответном сообщении на вкладке Инспекторы.

Снимок экрана: вкладка инспектора списка веб-сеансов с ответом

Необработанное сообщение http-ответа должно выглядеть примерно так:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/atomsvc+xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 17:51:01 GMT
Content-Length: 364

<?xml version="1.0" encoding="utf-8"?>
<service xml:base="http://localhost:60868/odata" 
    xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
  <workspace>
    <atom:title type="text">Default</atom:title>
    <collection href="Products">
        <atom:title type="text">Products</atom:title>
    </collection>
    </workspace>
</service></pre>

По умолчанию веб-API возвращает сервисный документ в формате AtomPub. Чтобы запросить JSON, добавьте следующий заголовок в HTTP-запрос:

Accept: application/json

Снимок экрана: окно веб-сеансов с ответом от API в разделе

Теперь HTTP-ответ содержит полезные данные JSON:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 22:59:28 GMT
Content-Length: 136

{
  "odata.metadata":"http://localhost:60868/odata/$metadata","value":[
    {
      "name":"Products","url":"Products"
    }
  ]
}

Документ метаданных службы

В документе метаданных службы описывается модель данных службы с использованием языка XML, называемого языком определения концептуальной схемы (CSDL). В документе метаданных показана структура данных в службе, которую можно использовать для создания клиентского кода.

Чтобы получить документ метаданных, отправьте запрос GET по адресу http://localhost:port/odata/$metadata. Ниже приведены метаданные для конечной точки, показанной в этом руководстве.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:05:52 GMT
Content-Length: 1086

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
  <edmx:DataServices m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <Schema Namespace="ProductService.Models" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
      <EntityType Name="Product">
        <Key>
          <PropertyRef Name="ID" />
        </Key>
        <Property Name="ID" Type="Edm.Int32" Nullable="false" />
        <Property Name="Name" Type="Edm.String" />
        <Property Name="Price" Type="Edm.Decimal" Nullable="false" />
        <Property Name="Category" Type="Edm.String" />
      </EntityType>
    </Schema>
    <Schema Namespace="Default" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
      <EntityContainer Name="Container" m:IsDefaultEntityContainer="true">
        <EntitySet Name="Products" EntityType="ProductService.Models.Product" />
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

Набор сущностей

Чтобы получить набор сущностей Products, отправьте запрос GET в http://localhost:port/odata/Products.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:01:31 GMT
Content-Length: 459

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products","value":[
    {
      "ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
    },{
      "ID":2,"Name":"Socks","Price":"5.00","Category":"Apparel"
    },{
      "ID":3,"Name":"Scarf","Price":"12.00","Category":"Apparel"
    },{
      "ID":4,"Name":"Yo-yo","Price":"4.95","Category":"Toys"
    },{
      "ID":5,"Name":"Puzzle","Price":"8.00","Category":"Toys"
    }
  ]
}

Сущность

Чтобы получить отдельный продукт, отправьте запрос GET на , http://localhost:port/odata/Products(1)где "1" — это идентификатор продукта.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:04:29 GMT
Content-Length: 140

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element","ID":1,
      "Name":"Hat","Price":"15.00","Category":"Apparel"
}

Форматы сериализации OData

OData поддерживает несколько форматов сериализации:

  • Atom Pub (XML)
  • JSON "light" (представлен в OData версии 3)
  • JSON "verbose" (OData версии 2)

По умолчанию веб-API использует "светлый" формат AtomPubJSON.

Чтобы получить формат AtomPub, задайте для заголовка Accept значение application/atom+xml. Вот пример тела запроса:

<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="http://localhost:60868/odata" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
  <id>http://localhost:60868/odata/Products(1)</id>
  <category term="ProductService.Models.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <link rel="edit" href="http://localhost:60868/odata/Products(1)" />
  <link rel="self" href="http://localhost:60868/odata/Products(1)" />
  <title />
  <updated>2013-09-23T23:42:11Z</updated>
  <author>
    <name />
  </author>
  <content type="application/xml">
    <m:properties>
      <d:ID m:type="Edm.Int32">1</d:ID>
      <d:Name>Hat</d:Name>
      <d:Price m:type="Edm.Decimal">15.00</d:Price>
      <d:Category>Apparel</d:Category>
    </m:properties>
  </content>
</entry>

Вы можете увидеть один очевидный недостаток формата Atom: он гораздо более подробный, чем json light. Однако если у вас есть клиент, который понимает AtomPub, клиент может предпочесть этот формат ВМЕСТО JSON.

Ниже приведена облегчаемая версия JSON той же сущности:

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element",
  "ID":1,
  "Name":"Hat",
  "Price":"15.00",
  "Category":"Apparel"
}

Светлый формат JSON появился в версии 3 протокола OData. Для обеспечения обратной совместимости клиент может запросить старый "подробный" формат JSON. Чтобы запросить подробный код JSON, задайте для заголовка Accept значение application/json;odata=verbose. Ниже приведена подробная версия:

{
  "d":{
    "__metadata":{
      "id":"http://localhost:18285/odata/Products(1)",
      "uri":"http://localhost:18285/odata/Products(1)",
      "type":"ProductService.Models.Product"
    },"ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
  }
}

Этот формат передает больше метаданных в тексте ответа, что может значительно повысить нагрузку на весь сеанс. Кроме того, он добавляет уровень косвенного обращения, упаковав объект в свойство с именем "d".

Next Steps