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


.Клиентская библиотека .NET (платформа служб данных ADO.NET)

В службы данных ADO.NET включена клиентская библиотека .NET для приложений, использующих платформу .NET Framework и службы данных ADO.NET. Приложения, использующие клиентскую библиотеку, работают с результатами, полученными от службы данных в виде объектов .NET. Прослеживание связей управляется объектами среды CLR.

В клиентской библиотеке .NET используется формат HTTP и AtomPub. Клиентская библиотека хорошо себя зарекомендовала в корпоративных сетях и интернет-средах. Все, что требуется — это возможность подключения на уровне HTTP к службе данных, напрямую или через прокси-сервер.

System.Data.Services.Client

Чтобы использовать клиентскую библиотеку, добавьте в проект ссылку на сборку System.Data.Services.Client. Клиентскую библиотеку можно использовать в проекте любого типа, включая проекты Windows Forms, Windows Presentation Foundation и веб-узлов.

Две основные конструкции клиентской библиотеки — класс DataServiceContext и класс DataServiceQuery. Класс DataServiceContext представляет контекст среды выполнения с заданной службой данных. Хотя службы данных и являются объектами без состояния, контекст таковым не является, и состояние клиента между взаимодействиями отслеживается для поддержки таких функций, как управление изменениями.

Класс DataServiceQuery представляет запрос к хранилищу, заданному с помощью синтаксиса URI служб данных ADO.NET. Чтобы выполнить запрос и получить результаты в форме объектов .NET, выполните перечисление объекта запроса, например, с помощью конструкции foreach в языке C# или For Each в Visual Basic.

Чтобы представить каждую сущность, определенную в службе данных, в форме объекта .NET, необходимо определить соответствующие классы для клиентского приложения. Например, можно определить классы вручную. Можно также использовать средство DataSvcUtil.exe, описание которого приведено в следующем подразделе.

В приведенном ниже примере показано определение для класса Address, созданное вручную на основе данных, представленных в образце базы данных AdventureWorks, которая поставляется вместе с SQL Server 2005. В примере используется сущность Address и небольшой фрагмент кода, выполняющего запрос к службе. Возвращаемые свойства сущности Address отображаются в качестве результата.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Services.Client;
    

namespace DataServiceClient
{

    public class Address
    {
        public int AddressID { get; set; }
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public string City { get; set; }
        public DateTime ModifiedDate { get; set; }
        public string PostalCode { get; set; }
        public Guid rowguid { get; set; }       
        public int StateProvinceID { get; set; }

    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }       


        private void button_Click(object sender, EventArgs e)
        {
            DataServiceContext ctx = new
                 DataServiceContext(new Uri("https://localhost:1492/AdvWksSales.svc/"));


          // This example expects the user to enter
             // an integer representing AddressID in textBox1.

             DataServiceQuery<Address> query =
                 ctx.CreateQuery<Address>(
                   "SalesOrderHeader(45678)/Address");

             StringBuilder output = new StringBuilder();
            
             foreach (Address address in query)
             {
                output.Append("Id: " + address.AddressID +
                        " Line 1: " + address.AddressLine1 + "\r\n");
                
             }

            richTextBox1.Text = output.ToString();
            


        }

Ниже показан результат.

Id: 70 Address Line1: 1792 Belmont Rd. City: Monroe

Использование средства DataSvcUtil

Создание классов вручную подходит для небольшого числа типов, но если схема службы данных достаточно сложная, то число и размер обслуживаемых классов увеличивается настолько, что обслуживать их вручную становится затруднительно. Лучше всего в этом случае использовать средство создания кода, которое называется DataSvcUtil.exe и поставляется вместе со службами данных ADO.NET. Это средство создает классы .NET из определения службы данных.

Средство DataSvcUtil.exe находится в каталоге «\WINDOWS\Microsoft.NET\Framework\v3.5\». В командной строке указывается аргумент: базовый URL-адрес службы данных, для которой нужно создать типы. Например, если служба Northwind выполняется на сервере разработки Visual Studio по адресу «https://localhost:1234/Northwind.svc», то командная строка для создания классов выглядит следующим образом:

C:\Program Files\Microsoft Visual Studio 9.0\VC>"C:\WINDOWS\Microsoft.NET\Framework\v3.5\DataSvcUtil.exe"
 /out:c:\northwind.cs /uri:https://localhost:1365/Northwind.svc

Результатом выполнения команды является файл C# (для создания типов Visual Basic используется переключатель /language:VB), содержащий класс для каждого типа сущности в службе данных.

Члены созданных классов представляют собой примитивные значения и связи, облегчающие перемещение по модели объекта.

Службы данных и LINQ to ADO.NET

В клиентской библиотеке .NET запросы службы данных поддерживаются с помощью запросов LINQ в дополнение к запросам, которые выполняются посредством вызова DataServiceContext.CreateQuery, как показано в разделе под заголовком «Веб-клиент данных Microsoft». Дополнительные сведения о LINQ см. в документе LINQ to Entities. В клиентской библиотеке обрабатывается информация о сопоставлении оператора LINQ с URI в целевой службе данных и получении указанных ресурсов в форме объектов .NET. В приведенном ниже примере показано, как получить список всех клиентов в городе Лондоне (London) и возвратить результирующий набор, упорядоченный по названию компании.

using System;
using System.Data.Services.Client;
using System.Linq;
using NorthwindModel;

namespace TestApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthwindEntities ctx = new 
            NorthwindEntities(
              new Uri("https://localhost:1365/Northwind.svc"));

            var q = from c in ctx.Customers 
                    where c.City == "London"
                    orderby c.CompanyName
                    select c;

            foreach (var cust in q)
            {
                Console.WriteLine(cust.CompanyName);
            }
        }
    }
}
NoteПримечание.

Набор запросов, которые можно выразить в синтаксисе LINQ, шире, чем набор запросов, поддерживаемых в URI-синтаксисе на основе технологии REST, который используется в службах данных. Исключение возникает, если запрос невозможно сопоставить с URI в целевой службе данных. Дополнительные сведения о концепции REST см. в разделе Службы REST и семантика (платформа служб данных ADO.NET).

NoteПримечание.

В примерах в этом разделе и двух следующих разделах используется образец базы данных Northwind. Базу данных Northwind можно загрузить с веб-страницы: https://go.microsoft.com/fwlink/?linkid=24758.

Связи

Связи между объектами отслеживаются и управляются классом DataServiceContext. Связанные объекты можно загружать «безотложно» или по мере необходимости. «Безотложная» и «неспешная» загрузки обсуждаются в документации ADO.NET Entity Framework в разделе Запрос данных как объектов и формирование результатов запроса (на английском языке). Форматы URL-адресов описаны в разделе Простая схема адресации для данных со стандартными URI (платформа служб данных ADO.NET).

Для загрузки связанных сущностей при необходимости используется метод LoadProperty в классе DataServiceContext. В приведенном ниже примере показано, как отложить загрузку сущностей Product, связанных с сущностями Category.

using System;
using System.Data.Services.Client;
using NorthwindModel;

namespace TestApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            DataServiceContext ctx = new
              DataServiceContext(
                  new Uri("https://localhost:1365/Northwind.svc"));

            DataServiceQuery<Categories> categories = 
                       ctx.CreateQuery<Categories>("/Categories");
            
            foreach (Categories c in categories)
            {
                 Console.WriteLine(c.CategoryName);

                 ctx.LoadProperty(c, "Products");

                 foreach (Products p in c.Products)
                 {
                    Console.WriteLine("\t" + p.ProductName);
                 }
              }
            }
        }
    }
}

Возможно, вам потребуется использовать связанные объекты в некоторых сценариях, и при их получении вы захотите избежать дополнительной задержки, связанной с дополнительным запросом. В этом случае можно использовать параметр expand внутри URL-адреса. Клиентская библиотека определяет, что результаты включают как сущности верхнего уровня, так и связанные сущности, и материализует их в виде графа объектов. Это называется «безотложной» загрузкой. Безотложная загрузка похожа на предыдущий пример, но при ее использовании связанные продукты загружаются в ходе одного кругового пути к службе данных.

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

using System;
using System.Data.Services.Client;
using NorthwindModel;

namespace TestApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            DataServiceContext ctx = new 
               DataServiceContext(
                      new Uri("https://localhost:1365/Northwind.svc"));

            // get a single category
            DataServiceQuery<Categories> categories = 
        ctx.CreateQuery<Categories>("/Categories(1)?$expand=Products");

            foreach (Categories c in categories)
            {
                //Console.WriteLine(c.CategoryName);
                richTextBox1.Text = c.CategoryName;

                foreach (Products p in c.Products)
                {
                    //Console.WriteLine("\t" + p.ProductName);
                    richTextBox1.Text = richTextBox1.Text + 
                                    "\r\n\t" + p.ProductName ;
                }
            }
        }
    }
}

Поддержка обновления

Чтобы создать новый экземпляр в службе данных, создайте объект .NET, затем вызовите AddObject для используемого экземпляра DataServiceContext, передавая объект и целевую сущность-набор, как показано в следующем фрагменте кода.

using System;
using Microsoft.Data.WebClient;
using NorthwindModel;

namespace TestApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            DataServiceContext ctx = new
              DataServiceContext(
                  new Uri("https://localhost:1365/Northwind.svc"));

            Categories cNew = new Categories();
            cNew.CategoryName = "NewCategory1";
            cNew.Description = "Add Item Test.";

            ctx.AddObject("Categories",cNew);
            ctx.SaveChanges();
        }
    }
}

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

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

NoteПримечание.

В приведенном ниже примере используется контекстный класс NorthwindEntities, который был создан выше с помощью средства создания кода и является производным от DataServiceContext. Этот производный класс предоставляет свойства, относящиеся непосредственно к службе, для упрощения написания кода для службы.

В приведенном ниже примере показан синтаксис обновления с использованием метода UpdateObject.

using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;

namespace TestApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthwindEntities ctxN =
               new NorthwindEntities(
                     new Uri("https://localhost:1365/Northwind.svc"));

            var c1 = (from c in ctxN.Categories
                     where c.CategoryName == "NewCategory1"
                     select c).First();
                               
            c1.CategoryName = "UpdatedCategory";

            //ctxN.AttachTo("Categories", c1);
            ctxN.UpdateObject(c1);
            ctxN.SaveChanges();
        }
    }
}

Чтобы удалить экземпляр сущности, вызовите метод Delete для объекта DataServiceContext.

Изменения отслеживаются в экземпляре DataServiceContext, но не отправляются на сервер немедленно. После завершения изменений для указанной операции вызовите метод SaveChanges, чтобы передать все изменения в службу данных.

Обновление связей

Инфраструктура обновления может также управлять изменениями связей. Она может изменять связи между объектами .NET и принуждать клиентскую библиотеку отражать эти изменения как операции создания или удаления связей в интерфейсе HTTP. В качестве иллюстрации в приведенном ниже примере в базе данных Northwind создается Product и связывается с существующей Category. Связи категорий и продуктов относятся к типу «один ко многим», поэтому для указанного продукта имеется одна определенная категория. В приведенном ниже примере кода показано, как использовать метод Add для связывания Product с Category.

using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;

namespace TestApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthwindEntities ctx = new 
             NorthwindEntities(new Uri(https://localhost:1234/Northwind.svc));
            
            var c1 = (from c in ctx.Categories
                     where c.CategoryName == "UpdatedCategory"
                     select c).First();

            Products p = new Products();
            p.ProductName = "TestProduct";
            p.Discontinued = false;
            p.QuantityPerUnit = "1";
            p.ReorderLevel = 100;
            p.UnitPrice = 1.1M;
            p.UnitsInStock = 200;
            p.UnitsOnOrder = 0;
            ctx.AddObject("Products", p);

            // Add binding between product and category
            p.Categories = c1;
            ctx.SetLink(p, "Categories", c1);

            ctx.SaveChanges();
            
            Console.ReadKey();
        }
    }

Управление изменениями в произвольных графах объектов с двунаправленными связями является сложной задачей; существуют расширенные библиотеки, например ADO.NET Entity Framework, предоставляющие согласованные диспетчеры состояний с большими возможностями для обработки графов с частичной материализацией. Клиентская библиотека ADO.NET, с другой стороны, рассчитана на минимальный объем памяти и предоставляет только те примитивы, которые необходимы для сопоставления операций службы данных с объектами .NET.

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

Цель →

Источник ↓

null

Added

Modified

Deleted

Unchanged

Added

SetLink

AddLink

SetLink

AddLink

SetLink

н/д

AddLink

SetLink

Modified

SetLink

AddLink

SetLink

AddLink

AttachLink

DeleteLink

SetLink

DeleteLink

AddLink

AttachLink

DeleteLink

SetLink

Deleted

SetLink

н/д

DeleteLink

DeleteLink

DeleteLink

Unchanged

SetLink

AddLink

AddLink

AttachLink

DeleteLink

SetLink

DeleteLink

AddLink

AttachLink

DeleteLink

SetLink

Метод AttachLink действует только в том случае, если и источник, и цель находятся в неизмененном состоянии. AttachLink не сохраняет отношения. Используйте метод AddLink, если только нужный результат предполагает несохранение ссылки посредством вызова SavingChanges.

Если имеется отношение между Products и Catagories, и свойство Products.Categories представляет собой коллекцию, используйте objCtx.AddLink(prod, "Categories", c1);

Если Products.Cateories является только ссылкой, используйте objCtx.SetLink(prod, "Categories", c1);

Когда выполняется метод SaveChanges для исходной сущности в состоянии Added, HTTP POST включает ссылки на другие сущности, находящиеся в измененном или неизмененном состоянии.

Метод AttachLink создает ссылку в состоянии EntityStates.Unchanged. С помощью такого механизма для пользователей создается ссылка, отслеживаемая в контексте, который не отправляется на сервер.

Проверка подлинности в клиентской библиотеке

При работе с протоколом HTTP клиентская библиотека .NET опирается на платформу .NET Framework. Помимо прочего инфраструктура .NET Framework автоматически обрабатывает схемы проверки подлинности через HTTP при предоставлении набора учетных данных.

По умолчанию клиентская библиотека не передает какие-либо учетные данные в стек HTTP. Однако можно задать свойство «Credentials» в DataServiceContext, чтобы указать объект, реализующий интерфейс ICredentials. Дополнительные сведения об учетных данных см. в документе WebRequest.Credentials.

Асинхронное взаимодействие со службой данных

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

В данной версии клиентская библиотека ADO.NET поддерживает асинхронный режим для большого числа операций, доступных в классе DataServiceContext, например для получения и сохранения изменений. В приведенном ниже примере показано, как используется в коде асинхронный интерфейс API клиентской библиотеки.

using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;

namespace TestApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthwindEntities ctx = new 
                NorthwindEntities(new Uri(https://localhost:51905/nw.svc));

            DataServiceQuery<Customers> q = ctx.Customers;

            q.BeginExecute(
                    delegate(IAsyncResult ar)
                    {
                        foreach (Customers c in q.EndExecute(ar))
                        {
                            Console.WriteLine(c.CompanyName);
                        }
                    },
                    null);


            Console.ReadKey();
        }
    }
}

См. также

Понятия

Метод GET в классе HttpWebRequest (платформа служб данных ADO.NET)
Создание служб данных ADO.NET

Другие ресурсы

Модель EDM