Создание конечной точки OData v3 с веб-API 2Creating an OData v3 Endpoint with Web API 2

по Майк Уоссонby Mike Wasson

Скачать завершенный проектDownload Completed Project

Open Data Protocol (OData) — это протокол доступа к данным для Интернета.The Open Data Protocol (OData) is a data access protocol for the web. OData обеспечивает единообразный способ структурирования данных, выполнения запросов к данным и управления набором данных с помощью операций CRUD (создание, чтение, обновление и удаление).OData provides a uniform way to structure data, query the data, and manipulate the data set through CRUD operations (create, read, update, and delete). OData поддерживает форматы AtomPub (XML) и JSON.OData supports both AtomPub (XML) and JSON formats. OData также определяет способ предоставления метаданных о данных.OData also defines a way to expose metadata about the data. Клиенты могут использовать метаданные для обнаружения сведений о типе и связей для набора данных.Clients can use the metadata to discover the type information and relationships for the data set.

Веб-API ASP.NET позволяет легко создать конечную точку OData для набора данных.ASP.NET Web API makes it easy to create an OData endpoint for a data set. Вы можете точно контролировать, какие операции OData поддерживает конечная точка.You can control exactly which OData operations the endpoint supports. Можно разместить несколько конечных точек OData вместе с конечными точками, отличными от OData.You can host multiple OData endpoints, alongside non-OData endpoints. Вы имеете полный контроль над моделью данных, внутренней бизнес-логикой и уровнем данных.You have full control over your data model, back-end business logic, and data layer.

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

Поддержка веб-API OData добавлена в ASP.NET and Web Tools обновление 2012,2.Web API OData support was added in ASP.NET and Web Tools 2012.2 Update. Однако в этом руководстве используется формирование шаблонов, добавленное в Visual Studio 2013.However, this tutorial uses scaffolding that was added in Visual Studio 2013.

В этом руководстве вы создадите простую конечную точку OData, которую клиенты смогут запрашивать.In this tutorial, you will create a simple OData endpoint that clients can query. Вы также создадите C# клиент для конечной точки.You will also create a C# client for the endpoint. После завершения работы с этим руководством в следующем наборе руководств показано, как добавить дополнительные функции, включая отношения сущностей, действия и $expand/$select.After you complete this tutorial, the next set of tutorials show how to add more functionality, including entity relations, actions, and $expand/$select.

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

В этом руководстве вы создадите конечную точку OData, которая поддерживает базовые операции CRUD.In this tutorial, you will create an OData endpoint that supports basic CRUD operations. Конечная точка будет предоставлять один ресурс, список продуктов.The endpoint will expose a single resource, a list of products. В последующих руководствах будут добавлены дополнительные функции.Later tutorials will add more features.

Запустите Visual Studio и выберите создать проект на начальной странице.Start Visual Studio and select New Project from the Start page. Либо в меню файл выберите создать , а затем — проект.Or, from the File menu, select New and then Project.

В области шаблоны выберите Установленные шаблоны и разверните узел визуального C# элемента.In the Templates pane, select Installed Templates and expand the Visual C# node. В разделе C#визуальный элемент выберите веб.Under Visual C#, select Web. Выберите шаблон веб-приложение ASP.NET .Select the ASP.NET Web Application template.

В диалоговом окне Новый проект ASP.NET выберите пустой шаблон.In the New ASP.NET Project dialog, select the Empty template. В разделе "добавить папки и основные ссылки для...", проверьте веб-API.Under "Add folders and core references for...", check Web API. Нажмите кнопку ОК.Click OK.

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

Модель — это объект, который представляет данные в приложении.A model is an object that represents the data in your application. Для работы с этим руководством нам нужна модель, представляющая продукт.For this tutorial, we need a model that represents a product. Модель соответствует типу сущности OData.The model corresponds to our OData entity type.

В обозревателе решений щелкните правой кнопкой мыши папку Models.In Solution Explorer, right-click the Models folder. В контекстном меню выберите Добавить, а затем выберите Класс.From the context menu, select Add then select Class.

В диалоговом окне Добавление нового элемента назовите класс ""продукта.In the Add New Item dialog, name the class "Product".

Note

По соглашению классы модели помещаются в папку Models.By convention, model classes are placed in the Models folder. Вам не нужно следовать этому соглашению в своих проектах, но мы будем использовать его в этом руководстве.You don't have to follow this convention in your own projects, but we'll use it for this tutorial.

В файле Product.cs добавьте следующее определение класса:In the Product.cs file, add the following class definition:

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

Свойство ID будет ключом сущности.The ID property will be the entity key. Клиенты могут запрашивать продукты по ИДЕНТИФИКАТОРу.Clients can query products by ID. Это поле также будет первичным ключом в серверной базе данных.This field would also be the primary key in the back-end database.

Постройте проект прямо сейчас.Build the project now. На следующем шаге мы будем использовать некоторые шаблоны Visual Studio, использующие отражение для поиска типа продукта.In the next step, we'll use some Visual Studio scaffolding that uses reflection to find the Product type.

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

Контроллер — это класс, который обрабатывает HTTP-запросы.A controller is a class that handles HTTP requests. Вы определяете отдельный контроллер для каждого набора сущностей в службе OData.You define a separate controller for each entity set in you OData service. В этом руководстве мы создадим один контроллер.In this tutorial, we'll create a single controller.

В обозреватель решений щелкните правой кнопкой мыши папку Controllers.In Solution Explorer, right-click the Controllers folder. Щелкните Добавить, а затем выберите Контроллер.Select Add and then select Controller.

В диалоговом окне Добавление шаблона выберите "контроллер OData веб-API 2 с действиями с помощью Entity Framework".In the Add Scaffold dialog, select "Web API 2 OData Controller with actions, using Entity Framework".

В диалоговом окне Добавление контроллера назовите контроллер «продуктсконтроллер».In the Add Controller dialog, name the controller "ProductsController". Установите флажок "использовать действия асинхронного контроллера".Select the "Use async controller actions" checkbox. В раскрывающемся списке модель выберите класс Product.In the Model drop-down list, select the Product class.

Нажмите кнопку создать контекст данных... .Click the New data context... button. Оставьте имя по умолчанию для типа контекста данных и нажмите кнопку Добавить.Leave the default name for the data context type, and click Add.

Нажмите кнопку Добавить в диалоговом окне Добавление контроллера, чтобы добавить контроллер.Click Add in the Add Controller dialog to add the controller.

Примечание. при получении сообщения об ошибке с сообщением "ошибка при получении типа..."убедитесь, что проект Visual Studio создан после добавления класса Product.Note: If you get an error message that says "There was an error getting the type...", make sure that you built the Visual Studio project after you added the Product class. Формирование шаблонов использует отражение для поиска класса.The scaffolding uses reflection to find the class.

Формирование шаблонов добавляет в проект два файла кода:The scaffolding adds two code files to the project:

  • Products.cs Определяет контроллер веб-API, который реализует конечную точку OData.Products.cs defines the Web API controller that implements the OData endpoint.
  • ProductServiceContext.cs предоставляет методы для запроса к базовой базе данных с помощью Entity Framework.ProductServiceContext.cs provides methods to query the underlying database, using Entity Framework.

Добавление модели EDM и маршрутаAdd the EDM and Route

В обозреватель решений разверните папку приложение_запуск и откройте файл с именем WebApiConfig.cs.In Solution Explorer, expand the App_Start folder and open the file named WebApiConfig.cs. Этот класс содержит код конфигурации для веб-API.This class holds configuration code for Web API. Замените этот код следующим:Replace this code with the following:

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());
        }
    }
}

Этот код выполняет два действия:This code does two things:

  • Создает EDM (модель EDM) для конечной точки OData.Creates an Entity Data Model (EDM) for the OData endpoint.
  • Добавляет маршрут для конечной точки.Adds a route for the endpoint.

EDM — это абстрактная модель данных.An EDM is an abstract model of the data. Модель EDM используется для создания документа метаданных и определения URI для службы.The EDM is used to create the metadata document and define the URIs for the service. Одатаконвентионмоделбуилдер создает EDM с помощью набора соглашений об именовании по умолчанию EDM.The ODataConventionModelBuilder creates an EDM by using a set of default naming conventions EDM. Этот подход требует наименьшего кода.This approach requires the least code. Если требуется больший контроль над EDM, можно использовать класс одатамоделбуилдер для создания модели EDM путем явного добавления свойств, ключей и свойств навигации.If you want more control over the EDM, you can use the ODataModelBuilder class to create the EDM by adding properties, keys, and navigation properties explicitly.

Метод EntitySet добавляет набор сущностей в модель EDM:The EntitySet method adds an entity set to the EDM:

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

Строка "Products" определяет имя набора сущностей.The string "Products" defines the name of the entity set. Имя контроллера должно совпадать с именем набора сущностей.The name of the controller must match the name of the entity set. В этом руководстве набор сущностей называется "Products", а контроллер называется ProductsController.In this tutorial, the entity set is named "Products" and the controller is named ProductsController. При именовании набора сущностей "набор продуктов" имя контроллера будет называться ProductSetController.If you named the entity set "ProductSet", you would name the controller ProductSetController. Обратите внимание, что конечная точка может иметь несколько наборов сущностей.Note that an endpoint can have multiple entity sets. Вызовите entityset<t> для каждого набора сущностей, а затем определите соответствующий контроллер.Call EntitySet<T> for each entity set, and then define a corresponding controller.

Метод маподатарауте добавляет маршрут для конечной точки OData.The MapODataRoute method adds a route for the OData endpoint.

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

Первый параметр — это понятное имя маршрута.The first parameter is a friendly name for the route. Клиенты службы не видят это имя.Clients of your service do not see this name. Вторым параметром является префикс URI для конечной точки.The second parameter is the URI prefix for the endpoint. Учитывая этот код, URI для набора сущностей Products — http://имя узла/одата/Продуктс.Given this code, the URI for the Products entity set is http://hostname/odata/Products. Приложение может иметь более одной конечной точки OData.Your application can have more than one OData endpoint. Для каждой конечной точки вызовите маподатарауте и укажите уникальное имя маршрута и уникальный префикс URI.For each endpoint, call MapODataRoute and provide a unique route name and a unique URI prefix.

Заполнение базы данных (необязательно)Seed the Database (Optional)

На этом шаге вы будете использовать Entity Framework для заполнения базы данных некоторыми тестовыми данными.In this step, you will use Entity Framework to seed the database with some test data. Этот шаг является необязательным, но он позволяет сразу же протестировать конечную точку OData.This step is optional, but it lets you test out your OData endpoint right away.

В меню Сервис выберите Диспетчер пакетов NuGet, а затем выберите консоль диспетчера пакетов.From the Tools menu, select NuGet Package Manager, then select Package Manager Console. В окне "Консоль диспетчера пакетов" введите следующую команду:In the Package Manager Console window, enter the following command:

Enable-Migrations

При этом добавляется папка с именем Migrations и файл кода с именем Configuration.cs.This adds a folder named Migrations and a code file named Configuration.cs.

Откройте этот файл и добавьте следующий код в метод Configuration.Seed.Open this file and add the following code to the Configuration.Seed method.

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" },
    });
}

В окне консоли диспетчера пакетов введите следующие команды:In the Package Manager Console Window, enter the following commands:

Add-Migration Initial
Update-Database

Эти команды создают код, который создает базу данных, а затем выполняет этот код.These commands generate code that creates the database, and then executes that code.

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

В этом разделе мы будем использовать прокси веб-отладки Fiddler для отправки запросов в конечную точку и проверки ответных сообщений.In this section, we'll use the Fiddler Web Debugging Proxy to send requests to the endpoint and examine the response messages. Это поможет понять возможности конечной точки OData.This will help you to understand the capabilities of an OData endpoint.

В Visual Studio нажмите клавишу F5, чтобы начать отладку.In Visual Studio, press F5 to start debugging. По умолчанию Visual Studio открывает браузер для http://localhost:*port*, где Port — номер порта, настроенный в параметрах проекта.By default, Visual Studio opens your browser to http://localhost:*port*, where port is the port number configured in the project settings.

Номер порта можно изменить в параметрах проекта.You can change the port number in the project settings. В обозреватель решений щелкните правой кнопкой мыши проект и выберите пункт Свойства.In Solution Explorer, right-click the project and select Properties. В окне Свойства выберите веб.In the properties window, select Web. Введите номер порта в поле URL-адрес проекта.Enter the port number under Project Url.

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

Сервисный документ содержит список наборов сущностей для конечной точки OData.The service document contains a list of the entity sets for the OData endpoint. Чтобы получить сервисный документ, отправьте запрос GET на корневой URI службы.To get the service document, send a GET request to the root URI of the service.

С помощью Fiddler введите следующий URI на вкладке Composer : http://localhost:port/odata/, где Port — номер порта.Using Fiddler, enter the following URI in the Composer tab: http://localhost:port/odata/, where port is the port number.

Нажмите кнопку Выполнить .Click the Execute button. Fiddler отправляет в приложение запрос HTTP GET.Fiddler sends an HTTP GET request to your application. Ответ должен отобразиться в списке веб-сеансов.You should see the response in the Web Sessions list. Если все работает, код состояния будет 200.If everything is working, the status code will be 200.

Дважды щелкните ответ в списке веб-сеансов, чтобы просмотреть подробные сведения о ответном сообщении на вкладке Инспекторы.Double-click the response in the Web Sessions list to see the details of the response message in the Inspectors tab.

Необработанное ответное сообщение HTTP должно выглядеть следующим образом:The raw HTTP response message should look similar to the following:

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.By default, Web API returns the service document in AtomPub format. Чтобы запросить JSON, добавьте следующий заголовок в HTTP-запрос:To request JSON, add the following header to the HTTP request:

Accept: application/json

Теперь ответ HTTP содержит полезные данные JSON:Now the HTTP response contains a JSON payload:

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"
    }
  ]
}

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

В документе метаданных службы описывается модель данных службы с помощью языка XML, который НАЗЫВАЕТСЯ языком CSDL.The service metadata document describes the data model of the service, using an XML language called the Conceptual Schema Definition Language (CSDL). В документе метаданных представлена структура данных в службе, которую можно использовать для создания клиентского кода.The metadata document shows the structure of the data in the service, and can be used to generate client code.

Чтобы получить документ метаданных, отправьте запрос GET в http://localhost:port/odata/$metadata.To get the metadata document, send a GET request to http://localhost:port/odata/$metadata. Ниже приведены метаданные для конечной точки, показанной в этом руководстве.Here is the metadata for the endpoint shown in this tutorial.

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>

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

Чтобы получить набор сущностей Products, отправьте запрос GET в http://localhost:port/odata/Products.To get the Products entity set, send a GET request to 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"
    }
  ]
}

СущностьEntity

Чтобы получить отдельный продукт, отправьте запрос GET в http://localhost:port/odata/Products(1), где "1" — это идентификатор продукта.To get an individual product, send a GET request to http://localhost:port/odata/Products(1), where "1" is the product ID.

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"
}

Форматы сериализации ODataOData Serialization Formats

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

  • Файл Atom (XML)Atom Pub (XML)
  • JSON "Light" (появился в OData v3)JSON "light" (introduced in OData v3)
  • JSON "verbose" (OData v2)JSON "verbose" (OData v2)

По умолчанию веб-API использует формат "Light" Атомпубжсон.By default, Web API uses AtomPubJSON "light" format.

Чтобы получить формат AtomPub, задайте для заголовка Accept значение "Application/Atom + XML".To get AtomPub format, set the Accept header to "application/atom+xml". Вот пример тела запроса:Here is an example response body:

<?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.You can see one obvious disadvantage of the Atom format: It's a lot more verbose than the JSON light. Однако если у вас есть клиент, который понимает AtomPub, клиент может предпочесть этот формат через JSON.However, if you have a client that understands AtomPub, the client might prefer that format over JSON.

Ниже приведена легкая версия JSON той же сущности:Here is the JSON light version of the same entity:

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

Формат JSON появился в версии 3 протокола OData.The JSON light format was introduced in version 3 of the OData protocol. Для обеспечения обратной совместимости клиент может запросить старый формат JSON "verbose".For backward compatibility, a client can request the older "verbose" JSON format. Чтобы запросить подробный JSON, задайте для заголовка Accept значение application/json;odata=verbose.To request verbose JSON, set the Accept header to application/json;odata=verbose. Ниже приведена подробная версия:Here is the verbose version:

{
  "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"
  }
}

Этот формат передает больше метаданных в тексте ответа, что может значительно увеличить нагрузку на весь сеанс.This format conveys more metadata in the response body, which can add considerable overhead over an entire session. Кроме того, он добавляет уровень косвенного обращения, упаковывая объект в свойство с именем «d».Also, it adds a level of indirection by wrapping the object in a property named "d".

Next StepsNext Steps