.NET 클라이언트 라이브러리(ADO.NET 데이터 서비스 프레임워크)
ADO.NET 데이터 서비스에는 .NET Framework 및 ADO.NET 데이터 서비스를 사용하는 응용 프로그램을 위한 .NET 클라이언트 라이브러리가 포함되어 있습니다. 이 클라이언트 라이브러리를 사용하는 응용 프로그램은 데이터 서비스로부터 .NET 개체로 받은 결과를 사용합니다. 연결 이동은 CLR(공용 언어 런타임) 개체를 통해 관리됩니다.
.NET 클라이언트 라이브러리는 HTTP 및 AtomPub 형식을 사용합니다. 이 클라이언트 라이브러리는 회사 네트워크 및 인터넷 환경에서 효과적으로 작동합니다. 직접 연결이든 프록시를 통한 연결이든 데이터 서비스에 대한 HTTP 수준 연결에서는 이 클라이언트 라이브러리만 있으면 됩니다.
System.Data.Services.Client
클라이언트 라이브러리를 사용하려면 System.Data.Services.Client 어셈블리에 대한 참조를 프로젝트에 추가해야 합니다. 클라이언트 라이브러리는 Windows Forms, Windows Presentation Foundation, 웹 사이트 프로젝트를 비롯한 모든 프로젝트 형식에서 사용할 수 있습니다.
클라이언트 라이브러리의 두 가지 주요 구문은 DataServiceContext
클래스 및 DataServiceQuery
클래스입니다. DataServiceContext
는 지정된 데이터 서비스가 있는 런타임 컨텍스트를 나타냅니다. 데이터 서비스는 상태 비저장 특성을 갖지만 컨텍스트는 그렇지 않습니다. 변경 관리 등의 기능을 지원하기 위해 상호 작용 간에 클라이언트에서 상태가 유지 관리됩니다.
DataServiceQuery
클래스는 ADO.NET 데이터 서비스 URI 구문을 사용하여 지정한 저장소에 대한 쿼리를 나타냅니다. 쿼리를 실행하고 .NET 개체 형식으로 결과를 가져오려면 foreach
구문(C#의 경우)이나 For Each
구문(Visual Basic의 경우)을 사용하여 쿼리 개체를 열거합니다.
데이터 서비스에 정의된 각 엔터티를 .NET 개체로 나타내려면 클라이언트 응용 프로그램에 대해 해당 클래스를 정의해야 합니다. 이를 수행하는 한 가지 방법은 클래스를 수동으로 정의하는 것입니다. 다른 방법은 이 문서의 뒷부분에서 설명하는 DataSvcUtil.exe 도구를 사용하는 것입니다.
다음 예제에서는 SQL Server 2005와 함께 제공된 AdventureWorks 샘플 데이터베이스의 데이터를 사용하여 직접 작성한 Address
클래스의 정의를 보여 줍니다. 이 예제에서는 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 도구 사용
클래스를 수동으로 작성하는 방법은 형식 수가 적을 때 적합합니다. 하지만 데이터 서비스 스키마가 복잡해지면 유지 관리해야 할 클래스의 규모도 커져 직접 관리하기가 어렵습니다. 이러한 경우에는 ADO.NET 데이터 서비스와 함께 제공되는 코드 생성 도구인 DataSvcUtil.exe를 사용하는 것이 좋습니다. 이 도구는 데이터 서비스 정의에서 .NET 클래스를 생성합니다.
DataSvcUtil.exe는 \WINDOWS\Microsoft.NET\Framework\v3.5\ 디렉터리에 있습니다. 명령줄에는 형식을 생성할 데이터 서비스에 대한 기본 URL을 인수로 사용합니다. 예를 들어 Northwind 서비스가 https://localhost:1234/Northwind.svc의 Visual Studio 개발 서버에서 실행 중인 경우 클래스를 생성하기 위한 명령줄은 다음과 같습니다.
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 클라이언트 라이브러리는 Microsoft 데이터 웹 클라이언트에 나오는 것처럼 DataServiceContext.CreateQuery
에 대한 호출에서 데이터 서비스를 쿼리하는 것 외에도 LINQ(Language-Integrated Queries)를 사용한 데이터 서비스 쿼리를 지원합니다. 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);
}
}
}
}
참고 |
---|
LINQ 구문으로 표현할 수 있는 쿼리 집합은 데이터 서비스에 사용되는 REST(Representational State Transfer) 기반 URI 구문에서 사용할 수 있는 것보다 광범위합니다. 쿼리를 대상 데이터 서비스의 URI에 매핑할 수 없으면 예외가 throw됩니다. REST에 대한 자세한 내용은 REST 서비스 및 의미 체계(ADO.NET 데이터 서비스 프레임워크)를 참조하십시오. |
참고 |
---|
이 단원 및 다음 두 단원의 예제에서는 Northwind 샘플 데이터베이스를 사용합니다. Northwind 샘플은 https://go.microsoft.com/fwlink/?linkid=24758에서 다운로드할 수 있습니다. |
연결
개체 간 연결은 DataServiceContext
클래스를 통해 추적 및 관리됩니다. 연결된 개체를 "즉시" 로드하거나 필요할 때 로드할 수 있습니다. "즉시" 로드 및 "지연" 로드에 대한 자세한 내용은 ADO.NET Entity Framework 설명서의 Querying Data as Objects and Shaping Query Results 항목을 참조하십시오. URL 형식은 URI를 사용한 단순한 데이터 주소 지정 스키마(ADO.NET 데이터 서비스 프레임워크)를 참조하십시오.
연결된 엔터티를 필요할 때 로드하는 경우에는 DataServiceContext
클래스의 LoadProperty
메서드가 사용됩니다. 다음 예제에서는 Category
엔터티와 연결된 Product
엔터티를 지연 로드하는 방법을 보여 줍니다.
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);
}
}
}
}
}
}
연결된 개체가 필요하지만 이러한 개체에 대한 검색 요청에서 추가적인 지연이 발생하는 것은 피하고 싶은 경우가 있습니다. 이런 경우 URL 내에서 expand
옵션을 사용할 수 있습니다. 클라이언트 라이브러리는 최상위 엔터티 및 연결된 엔터티가 모두 결과에 포함되어 있음을 인식하고 이들 모두를 하나의 개체 그래프로 구체화합니다. 이를 즉시 로드라고 합니다. 즉시 로드는 앞의 예제와 비슷하지만 관련된 제품을 데이터 서비스에 대한 한 번의 라운드트립으로 로드합니다.
다음 예제에서는 지정한 범주와 관련된 제품을 포함하는 expand 옵션을 보여 줍니다.
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 개체를 만든 후 다음 코드에서처럼 개체와 대상 엔터티 집합을 전달하여 사용할 DataServiceContext
인스턴스에 대해 AddObject
를 호출합니다.
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
메서드를 호출해 해당 개체의 업데이트를 보내야 한다고 클라이언트 라이브러리에 알립니다.
참고 |
---|
아래 예제에서는 위의 코드 생성 도구로 생성되었으며 |
다음 예제에서는 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();
}
}
}
엔터티 인스턴스를 삭제하려면 DataServiceContext
개체에 대해 Delete
메서드를 호출합니다.
변경 내용이 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 |
N/A |
AddLink SetLink |
Modified |
SetLink |
AddLink SetLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
Deleted |
SetLink |
N/A |
DeleteLink |
DeleteLink |
DeleteLink |
Unchanged |
SetLink |
AddLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
AttachLink는 소스와 대상의 상태가 모두 unchanged인 경우에만 작동합니다. AttachLink는 관계를 지속시키지 않습니다. SavingChanges에 대한 호출에서 링크를 저장하도록 하려는 경우가 아니라면 AddLink를 사용하지 마십시오.
Products
와 Catagories
간에 관계가 설정되어 있고 Products.Categories
속성이 컬렉션이면 objCtx.AddLink(prod, "Categories", c1)
를 사용하십시오.
Products.Cateories
가 참조일 뿐이면 objCtx.SetLink(prod, "Categories", c1);
를 사용하십시오.
Added
상태의 소스 엔터티에 대해 SaveChanges를 수행하는 동안 상태가 modified 또는 unchanged인 다른 엔터티에 대한 링크가 HTTP POST에 포함됩니다.
AttachLink 메서드는 EntityStates.Unchanged
상태의 링크를 만듭니다. 이는 서버로 전송되지 않는 컨텍스트를 통해 추적되는 링크를 만들려는 사용자에게 유용한 메커니즘입니다.
클라이언트 라이브러리의 인증
.NET 클라이언트 라이브러리는 HTTP 프로토콜에 대한 .NET Framework 지원을 사용합니다. 무엇보다도 프레임워크 인프라는 자격 증명 집합이 제공될 경우 HTTP를 통한 인증 스키마를 자동으로 처리합니다.
클라이언트 라이브러리는 기본적으로 HTTP 스택에 어떠한 자격 증명도 제공하지 않습니다. 하지만 DataServiceContext
에서 Credentials 속성을 설정하여 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();
}
}
}
참고 항목
개념
HttpWebRequest GET(ADO.NET 데이터 서비스 프레임워크)
ADO.NET 데이터 서비스 만들기