.NET 클라이언트 (C#)에서 Web API 호출Call a Web API From a .NET Client (C#)

하 여 Mike WassonRick Andersonby Mike Wasson and Rick Anderson

완료 된 프로젝트 다운로드합니다.Download Completed Project. 지침을 다운로드하세요.Download instructions.

이 자습서에서는.NET 응용 프로그램, web API를 호출 하는 방법을 보여 줍니다.를 사용 하 여 System.Net.Http.HttpClient 합니다.This tutorial shows how to call a web API from a .NET application, using System.Net.Http.HttpClient.

이 자습서에서는 다음 웹 API를 사용 하는 클라이언트 앱을 작성 됩니다.In this tutorial, a client app is written that consumes the following web API:

작업Action HTTP 메서드HTTP method 상대 URIRelative URI
제품 ID 별로 가져오기Get a product by ID 가져오기GET /api/products/id/api/products/id
새 제품 만들기Create a new product 올리기POST api 제품/api/products
제품 업데이트Update a product PUTPUT /api/products/id/api/products/id
제품 삭제Delete a product DeleteDELETE /api/products/id/api/products/id

참조를 ASP.NET Web API를 사용 하 여이 API를 구현 하는 방법을 알아보려면 Web API에서는 CRUD 작업을 만드는합니다.To learn how to implement this API with ASP.NET Web API, see Creating a Web API that Supports CRUD Operations.

간단히 하기 위해이 자습서에서는 클라이언트 응용 프로그램은 Windows 콘솔 응용 프로그램입니다.For simplicity, the client application in this tutorial is a Windows console application. HttpClient Windows Phone 및 Windows 스토어 앱도 지원 됩니다.HttpClient is also supported for Windows Phone and Windows Store apps. 자세한 내용은 참조 하세요. 여러 플랫폼 이식 가능한 라이브러리 사용에 대 한 웹 API 클라이언트 코드 작성For more information, see Writing Web API Client Code for Multiple Platforms Using Portable Libraries

콘솔 응용 프로그램 만들기Create the Console Application

Visual Studio에서 명명 된 새 Windows 콘솔 앱을 만듭니다 HttpClientSample 다음 코드에 붙여 넣습니다.In Visual Studio, create a new Windows console app named HttpClientSample and paste in the following code:

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace HttpClientSample
{
    public class Product
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public string Category { get; set; }
    }

    class Program
    {
        static HttpClient client = new HttpClient();

        static void ShowProduct(Product product)
        {
            Console.WriteLine($"Name: {product.Name}\tPrice: " +
                $"{product.Price}\tCategory: {product.Category}");
        }

        static async Task<Uri> CreateProductAsync(Product product)
        {
            HttpResponseMessage response = await client.PostAsJsonAsync(
                "api/products", product);
            response.EnsureSuccessStatusCode();

            // return URI of the created resource.
            return response.Headers.Location;
        }

        static async Task<Product> GetProductAsync(string path)
        {
            Product product = null;
            HttpResponseMessage response = await client.GetAsync(path);
            if (response.IsSuccessStatusCode)
            {
                product = await response.Content.ReadAsAsync<Product>();
            }
            return product;
        }

        static async Task<Product> UpdateProductAsync(Product product)
        {
            HttpResponseMessage response = await client.PutAsJsonAsync(
                $"api/products/{product.Id}", product);
            response.EnsureSuccessStatusCode();

            // Deserialize the updated product from the response body.
            product = await response.Content.ReadAsAsync<Product>();
            return product;
        }

        static async Task<HttpStatusCode> DeleteProductAsync(string id)
        {
            HttpResponseMessage response = await client.DeleteAsync(
                $"api/products/{id}");
            return response.StatusCode;
        }

        static void Main()
        {
            RunAsync().GetAwaiter().GetResult();
        }

        static async Task RunAsync()
        {
            // Update port # in the following line.
            client.BaseAddress = new Uri("http://localhost:64195/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));

            try
            {
                // Create a new product
                Product product = new Product
                {
                    Name = "Gizmo",
                    Price = 100,
                    Category = "Widgets"
                };

                var url = await CreateProductAsync(product);
                Console.WriteLine($"Created at {url}");

                // Get the product
                product = await GetProductAsync(url.PathAndQuery);
                ShowProduct(product);

                // Update the product
                Console.WriteLine("Updating price...");
                product.Price = 80;
                await UpdateProductAsync(product);

                // Get the updated product
                product = await GetProductAsync(url.PathAndQuery);
                ShowProduct(product);

                // Delete the product
                var statusCode = await DeleteProductAsync(product.Id);
                Console.WriteLine($"Deleted (HTTP Status = {(int)statusCode})");

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            Console.ReadLine();
        }
    }
}

위의 코드는 전체 클라이언트 앱입니다.The preceding code is the complete client app.

RunAsync 실행 및 완료 될 때까지 차단 합니다.RunAsync runs and blocks until it completes. 대부분 HttpClient 메서드는 비동기, 네트워크 I/O를 수행 하는 때문에 있습니다.Most HttpClient methods are async, because they perform network I/O. 내부에서 수행 하는 비동기 작업을 모두 RunAsync입니다.All of the async tasks are done inside RunAsync. 일반적으로 앱 주 스레드를 차단 하지 않습니다 하지만이 앱이 모든 상호 작용을 허용 하지 않습니다.Normally an app doesn't block the main thread, but this app doesn't allow any interaction.

static async Task RunAsync()
{
    // Update port # in the following line.
    client.BaseAddress = new Uri("http://localhost:64195/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));

    try
    {
        // Create a new product
        Product product = new Product
        {
            Name = "Gizmo",
            Price = 100,
            Category = "Widgets"
        };

        var url = await CreateProductAsync(product);
        Console.WriteLine($"Created at {url}");

        // Get the product
        product = await GetProductAsync(url.PathAndQuery);
        ShowProduct(product);

        // Update the product
        Console.WriteLine("Updating price...");
        product.Price = 80;
        await UpdateProductAsync(product);

        // Get the updated product
        product = await GetProductAsync(url.PathAndQuery);
        ShowProduct(product);

        // Delete the product
        var statusCode = await DeleteProductAsync(product.Id);
        Console.WriteLine($"Deleted (HTTP Status = {(int)statusCode})");

    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    Console.ReadLine();
}

웹 API 클라이언트 라이브러리 설치Install the Web API Client Libraries

NuGet 패키지 관리자를 사용 하 여 웹 API 클라이언트 라이브러리 패키지를 설치 합니다.Use NuGet Package Manager to install the Web API Client Libraries package.

도구 메뉴에서 NuGet 패키지 관리자 > 패키지 관리자 콘솔을 선택합니다.From the Tools menu, select NuGet Package Manager > Package Manager Console. 에 콘솔 PMC (패키지 관리자), 다음 명령을 입력 합니다.In the Package Manager Console (PMC), type the following command:

Install-Package Microsoft.AspNet.WebApi.Client

위의 명령은 프로젝트에 다음 NuGet 패키지를 추가합니다.The preceding command adds the following NuGet packages to the project:

  • Microsoft.AspNet.WebApi.ClientMicrosoft.AspNet.WebApi.Client
  • Newtonsoft.JsonNewtonsoft.Json

Json.NET은.NET에 대 한 인기 있는 고성능 JSON 프레임 워크입니다.Json.NET is a popular high-performance JSON framework for .NET.

모델 클래스 추가Add a Model Class

Product 클래스를 검사합니다.Examine the Product class:

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

이 클래스는 웹 API에 의해 사용 되는 데이터 모델을 찾습니다.This class matches the data model used by the web API. 앱에서 사용할 수 있습니다 HttpClient 읽을 수는 Product HTTP 응답 인스턴스입니다.An app can use HttpClient to read a Product instance from an HTTP response. 앱은 deserialization 코드를 작성할 필요가 없습니다.The app doesn't have to write any deserialization code.

만들기 및 HttpClient를 초기화 합니다.Create and Initialize HttpClient

정적 검사 HttpClient 속성:Examine the static HttpClient property:

static HttpClient client = new HttpClient();

HttpClient 한 번 인스턴스화되면 되 고 응용 프로그램의 수명 내내 다시 사용 합니다.HttpClient is intended to be instantiated once and reused throughout the life of an application. 다음 조건이 발생할 수 있습니다 SocketException 오류:The following conditions can result in SocketException errors:

  • 새로 만들 HttpClient 요청당 인스턴스.Creating a new HttpClient instance per request.
  • 부하가 서버입니다.Server under heavy load.

새로 만들 HttpClient 요청당 인스턴스는 사용 가능한 소켓 소모 될 수 있습니다.Creating a new HttpClient instance per request can exhaust the available sockets.

다음 코드는 초기화 된 HttpClient 인스턴스:The following code initializes the HttpClient instance:

static async Task RunAsync()
{
    // Update port # in the following line.
    client.BaseAddress = new Uri("http://localhost:64195/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));

위의 코드는:The preceding code:

  • HTTP 요청에 대 한 기본 URI를 설정합니다.Sets the base URI for HTTP requests. 서버 앱에서 사용 되는 포트를 포트 번호를 변경 합니다.Change the port number to the port used in the server app. 앱 서버 앱에 대 한 포트를 사용 하지 않으면 작동 하지 않습니다.The app won't work unless port for the server app is used.
  • Accept 헤더가 "application/json"으로 설정합니다.Sets the Accept header to "application/json". 이 헤더를 설정 합니다. JSON 형식으로 데이터를 보내도록 서버에 알려 줍니다.Setting this header tells the server to send data in JSON format.

리소스를 검색에 GET 요청을 보냄Send a GET request to retrieve a resource

다음 코드는 제품에 대 한 GET 요청을 보냅니다.The following code sends a GET request for a product:

static async Task<Product> GetProductAsync(string path)
{
    Product product = null;
    HttpResponseMessage response = await client.GetAsync(path);
    if (response.IsSuccessStatusCode)
    {
        product = await response.Content.ReadAsAsync<Product>();
    }
    return product;
}

합니다 GetAsync 메서드는 HTTP GET 요청을 보냅니다.The GetAsync method sends the HTTP GET request. 메서드가 완료 되 면 반환 된 HttpResponseMessage HTTP 응답을 포함 하는 합니다.When the method completes, it returns an HttpResponseMessage that contains the HTTP response. 응답에 상태 코드가 성공 코드 인 경우 응답 본문에는 제품의 JSON 표현을 포함 합니다.If the status code in the response is a success code, the response body contains the JSON representation of a product. 호출 ReadAsAsync JSON 페이로드를 deserialize 하는 데는 Product 인스턴스.Call ReadAsAsync to deserialize the JSON payload to a Product instance. 합니다 ReadAsAsync 메서드는 응답 본문은 임의로 큰 수 있기 때문에 비동기입니다.The ReadAsAsync method is asynchronous because the response body can be arbitrarily large.

HttpClient HTTP 응답 오류 코드를 포함 하는 경우 예외를 throw 하지 않습니다.HttpClient does not throw an exception when the HTTP response contains an error code. 대신 합니다 IsSuccessStatusCode 속성은 false 상태가 오류 코드입니다.Instead, the IsSuccessStatusCode property is false if the status is an error code. HTTP 오류 코드를 예외로 처리 하는 것을 선호 하는 경우 호출 HttpResponseMessage.EnsureSuccessStatusCode 응답 개체입니다.If you prefer to treat HTTP error codes as exceptions, call HttpResponseMessage.EnsureSuccessStatusCode on the response object. EnsureSuccessStatusCode 상태 코드 200 범위를 벗어나는 경우 예외를 throw–299 합니다.EnsureSuccessStatusCode throws an exception if the status code falls outside the range 200–299. 사실은 HttpClient 다른 이유로 예외를 throw 할 수 있습니다 — 예를 들어 요청 시간이 초과 됩니다.Note that HttpClient can throw exceptions for other reasons — for example, if the request times out.

Deserialize 하는 미디어 유형 포맷터Media-Type Formatters to Deserialize

ReadAsAsync 라고 일련의 기본 매개 변수 없이 사용 미디어 포맷터 응답 본문을 읽을 수 있습니다.When ReadAsAsync is called with no parameters, it uses a default set of media formatters to read the response body. 기본 포맷터는 JSON, XML 및 양식 url로 인코딩된 데이터를 지원합니다.The default formatters support JSON, XML, and Form-url-encoded data.

기본 포맷터를 사용 하는 대신 하는 포맷터의 목록을 제공할 수 있습니다 합니다 ReadAsAsync 메서드.Instead of using the default formatters, you can provide a list of formatters to the ReadAsAsync method. 포맷터 목록을 사용 하 여는 사용자 지정 미디어 유형 포맷터를 해야 하는 경우에 유용 합니다.Using a list of formatters is useful if you have a custom media-type formatter:

var formatters = new List<MediaTypeFormatter>() {
    new MyCustomFormatter(),
    new JsonMediaTypeFormatter(),
    new XmlMediaTypeFormatter()
};
resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);

자세한 내용은 참조 하세요. ASP.NET Web API 2의 미디어 포맷터For more information, see Media Formatters in ASP.NET Web API 2

리소스를 만드는 POST 요청Sending a POST Request to Create a Resource

다음 코드를 포함 하는 POST 요청이 전송 된 Product JSON 형식으로 인스턴스:The following code sends a POST request that contains a Product instance in JSON format:

static async Task<Uri> CreateProductAsync(Product product)
{
    HttpResponseMessage response = await client.PostAsJsonAsync(
        "api/products", product);
    response.EnsureSuccessStatusCode();

    // return URI of the created resource.
    return response.Headers.Location;
}

합니다 PostAsJsonAsync 메서드:The PostAsJsonAsync method:

  • Json 개체를 serialize합니다.Serializes an object to JSON.
  • POST 요청에 JSON 페이로드를 보냅니다.Sends the JSON payload in a POST request.

요청이 성공 합니다.If the request succeeds:

  • 201 (만들어짐) 응답을 반환 해야 합니다.It should return a 201 (Created) response.
  • 응답의 Location 헤더의 생성된 된 리소스의 URL을 포함 해야 합니다.The response should include the URL of the created resources in the Location header.

리소스를 업데이트 하는 PUT 요청을 보내기Sending a PUT Request to Update a Resource

다음 코드는 제품을 업데이트 하는 PUT 요청을 보냅니다.The following code sends a PUT request to update a product:

static async Task<Product> UpdateProductAsync(Product product)
{
    HttpResponseMessage response = await client.PutAsJsonAsync(
        $"api/products/{product.Id}", product);
    response.EnsureSuccessStatusCode();

    // Deserialize the updated product from the response body.
    product = await response.Content.ReadAsAsync<Product>();
    return product;
}

합니다 PutAsJsonAsync 메서드처럼 작동 PostAsJsonAsyncPOST 대신 PUT 요청을 전송 하는 점을 제외 하 고, 합니다.The PutAsJsonAsync method works like PostAsJsonAsync, except that it sends a PUT request instead of POST.

리소스를 삭제 하는 DELETE 요청을 보내기Sending a DELETE Request to Delete a Resource

다음 코드는 제품을 삭제 하는 DELETE 요청을 보냅니다.The following code sends a DELETE request to delete a product:

static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
    HttpResponseMessage response = await client.DeleteAsync(
        $"api/products/{id}");
    return response.StatusCode;
}

GET, 같은 삭제 요청 되지 않은 요청 본문입니다.Like GET, a DELETE request does not have a request body. 삭제를 사용 하 여 JSON 또는 XML 형식으로 지정할 필요가 없습니다.You don't need to specify JSON or XML format with DELETE.

샘플 테스트Test the sample

클라이언트 앱을 테스트 합니다.To test the client app:

  1. 다운로드 및 서버 앱을 실행 합니다.Download and run the server app. 지침을 다운로드하세요.Download instructions. 서버 앱이 작동을 확인 합니다.Verify the server app is working. 예를 들어 http://localhost:64195/api/products 제품 목록을 반환 해야 합니다.For example, http://localhost:64195/api/products should return a list of products.

  2. HTTP 요청에 대 한 기본 URI를 설정 합니다.Set the base URI for HTTP requests. 서버 앱에서 사용 되는 포트를 포트 번호를 변경 합니다.Change the port number to the port used in the server app.

    static async Task RunAsync()
    {
        // Update port # in the following line.
        client.BaseAddress = new Uri("http://localhost:64195/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));
    
  3. 클라이언트 앱을 실행 합니다.Run the client app. 다음 출력이 생성됩니다.The following output is produced:

    Created at http://localhost:64195/api/products/4
    Name: Gizmo     Price: 100.0    Category: Widgets
    Updating price...
    Name: Gizmo     Price: 80.0     Category: Widgets
    Deleted (HTTP Status = 204)