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

만든 사람 Mike Wasson And Rick Andersonby Mike Wasson and Rick Anderson

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

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

이 자습서에서는 다음 web 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 GETGET /api/products/id/api/products/id
새 제품 만들기Create a new product POSTPOST /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를 구현 하는 방법을 알아보려면 CRUD 작업을 지 원하는 WEB API 만들기를 참조 하세요.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. 자세한 내용은 이식 가능한 라이브러리를 사용 하 여 여러 플랫폼에 대 한 WEB API 클라이언트 코드 작성 을 참조 하세요.For more information, see Writing Web API Client Code for Multiple Platforms Using Portable Libraries

참고: 기본 Url과 상대 Uri를 하드 코드 된 값으로 전달 하는 경우 API를 활용 하는 규칙에 주의 해야 합니다 HttpClient .NOTE: If you pass base URLs and relative URIs as hard-coded values, be mindful of the rules for utilizing the HttpClient API. HttpClient.BaseAddress속성은 후행 슬래시 ()로 주소를 설정 해야 합니다 / .The HttpClient.BaseAddress property should be set to an address with a trailing forward slash (/). 예를 들어 하드 코드 된 리소스 Uri를 메서드에 전달할 때 HttpClient.GetAsync 선행 슬래시를 포함 하지 않습니다.For example, when passing hard-coded resource URIs to the HttpClient.GetAsync method, don't include a leading forward slash. ProductID로을 가져오려면 다음을 수행 합니다.To get a Product by ID:

  1. 설정client.BaseAddress = new Uri("https://localhost:5001/");Set client.BaseAddress = new Uri("https://localhost:5001/");
  2. 을 요청 Product 합니다.Request a Product. 예: client.GetAsync<Product>("api/products/4");.For example, client.GetAsync<Product>("api/products/4");.

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

Visual Studio에서 Httpclientsample 이라는 새 Windows 콘솔 앱을 만들고 다음 코드를 붙여 넣습니다.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();
}

Web API 클라이언트 라이브러리를 설치 합니다.Install the Web API Client Libraries

NuGet 패키지 관리자를 사용 하 여 Web 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:

  • WebApi. 클라이언트Microsoft.AspNet.WebApi.Client
  • Newtonsoft.JsonNewtonsoft.Json

Netwonsoft (Json.NET 라고도 함)는 .NET 용으로 널리 사용 되는 고성능 JSON 프레임 워크입니다.Netwonsoft.Json (also known as 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; }
}

이 클래스는 web 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. 메서드가 완료 되 면 HTTP 응답을 포함 하는 HttpResponseMessage 를 반환 합니다.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 페이로드를 Product 인스턴스로 deserialize 합니다.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.

HTTP 응답에 오류 코드가 포함 되어 있으면 Httpclient 는 예외를 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 를 호출 합니다.If you prefer to treat HTTP error codes as exceptions, call HttpResponseMessage.EnsureSuccessStatusCode on the response object. EnsureSuccessStatusCode상태 코드가 200 299 범위를 벗어나면 예외가 throw 됩니다 – .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

다음 코드는 Product 인스턴스를 JSON 형식으로 포함 하는 POST 요청을 보냅니다.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 (Created) 응답을 반환 해야 합니다.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 메서드는 POST 대신 PUT 요청을 전송 한다는 점을 제외 하 고는 PostAsJsonAsync와 유사 하 게 작동 합니다.The PutAsJsonAsync method works like PostAsJsonAsync, except that it sends a PUT request instead of POST.

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

다음 코드는 제품을 삭제 하는 삭제 요청을 보냅니다.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과 마찬가지로 DELETE 요청에는 요청 본문이 없습니다.Like GET, a DELETE request does not have a request body. DELETE를 사용 하 여 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)