Cliente RESTREST client

IntroduçãoIntroduction

Este tutorial ensina vários recursos no .NET Core e da linguagem C#.This tutorial teaches you a number of features in .NET Core and the C# language. Você aprenderá:You’ll learn:

  • As noções básicas da CLI (Interface de Linha de Comando) do .NET Core.The basics of the .NET Core Command Line Interface (CLI).
  • Uma visão geral dos recursos da linguagem C#.An overview of C# Language features.
  • Gerenciamento de dependências com o NuGetManaging dependencies with NuGet
  • Comunicações HTTPHTTP Communications
  • Processamento de informações de JSONProcessing JSON information
  • Gerenciamento de configuração com Atributos.Managing configuration with Attributes.

Você compilará um aplicativo que emite solicitações HTTP para um serviço REST no GitHub.You’ll build an application that issues HTTP Requests to a REST service on GitHub. Você lerá informações no formato JSON e converterá esse pacote JSON em objetos C#.You'll read information in JSON format, and convert that JSON packet into C# objects. Por fim, você verá como trabalhar com objetos C#.Finally, you'll see how to work with C# objects.

Há vários recursos neste tutorial.There are a lot of features in this tutorial. Vamos compilá-los individualmente.Let’s build them one by one.

Se preferir acompanhar com o exemplo final para esse tópico, você poderá baixá-lo.If you prefer to follow along with the final sample for this topic, you can download it. Para obter instruções de download, consulte Exemplos e tutoriais.For download instructions, see Samples and Tutorials.

Pré-requisitosPrerequisites

Você precisará configurar seu computador para executar o .NET Core.You’ll need to set up your machine to run .NET core. Você pode encontrar as instruções de instalação na página de downloads do .NET Core .You can find the installation instructions on the .NET Core Downloads page. Execute esse aplicativo no Windows, Linux, macOS ou em um contêiner do Docker.You can run this application on Windows, Linux, macOS or in a Docker container. Será necessário instalar o editor de código de sua preferência.You’ll need to install your favorite code editor. As descrições a seguir usam o Visual Studio Code, que é uma software livre, no editor de plataforma.The descriptions below use Visual Studio Code, which is an open source, cross platform editor. No entanto, você pode usar quaisquer ferramentas que esteja familiarizado.However, you can use whatever tools you are comfortable with.

Criar o aplicativoCreate the Application

A primeira etapa é criar um novo aplicativo.The first step is to create a new application. Abra um prompt de comando e crie um novo diretório para seu aplicativo.Open a command prompt and create a new directory for your application. Torne ele o diretório atual.Make that the current directory. Digite o comando dotnet new console no prompt de comando.Type the command dotnet new console at the command prompt. Isso cria os arquivos iniciais de um aplicativo "Olá, Mundo" básico.This creates the starter files for a basic "Hello World" application. Como esse é um novo projeto, nenhuma das dependências está em vigor, portanto, a primeira execução baixará o .NET Core Framework, instalará um certificado de desenvolvimento e executará o gerenciador de pacotes do NuGet para restaurar dependências ausentes.As this is a new project, none of the dependencies are in place, so the first run will download the .NET Core framework, install a development certificate and run the NuGet package manager to restore missing dependencies.

Antes de começar a fazer modificações, digite dotnet run (veja a observação) no prompt de comando para executar seu aplicativo.Before you start making modifications, type dotnet run (see note) at the command prompt to run your application. dotnet run executará automaticamente dotnet restore se estiverem faltando dependências em seu ambiente.dotnet run automatically performs dotnet restore if your environment is missing dependencies. Ele também executará dotnet build se seu aplicativo precisar ser reconstruído.It also performs dotnet build if your application needs to be rebuilt. Após sua configuração inicial, você só precisará executar dotnet restore ou dotnet build quando fizer sentido para seu projeto.After your initial setup, you will only need to run dotnet restore or dotnet build when it makes sense for your project.

Adicionar novas dependênciasAdding New Dependencies

Uma das principais metas de design para o .NET Core é minimizar o tamanho da instalação do .NET.One of the key design goals for .NET Core is to minimize the size of the .NET installation. Se um aplicativo precisar de mais bibliotecas para alguns de seus recursos, adicione essas dependências ao seu arquivo de projeto de C# (*.csproj).If an application needs additional libraries for some of its features, you add those dependencies into your C# project (*.csproj) file. Para nosso exemplo, você precisará adicionar o pacote System.Runtime.Serialization.Json para que seu aplicativo possa processar as respostas em JSON.For our example, you'll need to add the System.Runtime.Serialization.Json package so your application can process JSON responses.

Abra seu arquivo de projeto csproj.Open your csproj project file. A primeira linha do arquivo deve aparecer assim:The first line of the file should appear as:

<Project Sdk="Microsoft.NET.Sdk">

Adicione o seguinte logo após esta linha:Add the following immediately after this line:

   <ItemGroup>
      <PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
   </ItemGroup>

A maioria dos editores de código fornece conclusão para versões diferentes dessas bibliotecas.Most code editors will provide completion for different versions of these libraries. Convém usar a versão mais recente de qualquer pacote que você adicionar.You'll usually want to use the latest version of any package that you add. No entanto, é importante ter certeza de que as versões de todos os pacotes correspondam, e que também correspondam à versão da estrutura de aplicativo do .NET Core.However, it is important to make sure that the versions of all packages match, and that they also match the version of the .NET Core Application framework.

Após fazer essas alterações, execute dotnet restore (veja a observação) para que o pacote seja instalado em seu sistema.After you've made these changes, execute dotnet restore (see note) so that the package is installed on your system.

Como fazer solicitações da WebMaking Web Requests

Agora você está pronto para começar a obter dados da Web.Now you're ready to start retrieving data from the web. Neste aplicativo, você lerá informações da API do GitHub.In this application, you'll read information from the GitHub API. Vamos ler informações sobre os projetos em .NET Foundation.Let's read information about the projects under the .NET Foundation umbrella. Comece fazendo a solicitação à API do GitHub para recuperar informações sobre os projetos.You'll start by making the request to the GitHub API to retrieve information on the projects. O ponto de extremidade que você usará é: https://api.github.com/orgs/dotnet/repos.The endpoint you'll use is: https://api.github.com/orgs/dotnet/repos. Você quer obter todas as informações sobre esses projetos, portanto, use uma solicitação HTTP GET.You want to retrieve all the information about these projects, so you'll use an HTTP GET request. O navegador também usa solicitações HTTP GET, para que você possa colar essa URL em seu navegador e ver as informações que receberá.Your browser also uses HTTP GET requests, so you can paste that URL into your browser to see what information you'll be receiving and processing.

Use a classe HttpClient para fazer solicitações da Web.You use the HttpClient class to make web requests. Como todas as APIs .NET modernas, a HttpClient oferece suporte apenas aos métodos assíncronos para suas APIs de longa execução.Like all modern .NET APIs, HttpClient supports only async methods for its long-running APIs. Comece criando um método assíncrono.Start by making an async method. Você preencherá a implementação à medida que compila a funcionalidade do aplicativo.You'll fill in the implementation as you build the functionality of the application. Comece abrindo o arquivo program.cs no diretório do projeto e adicionando o seguinte método à classe Program:Start by opening the program.cs file in your project directory and adding the following method to the Program class:

private static async Task ProcessRepositories()
{
}

Será necessário adicionar uma instrução using na parte superior de seu método Main para que o compilador de C# reconheça o tipo Task:You'll need to add a using statement at the top of your Main method so that the C# compiler recognizes the Task type:

using System.Threading.Tasks;

Se você compilar o projeto neste momento, receberá um aviso gerado para esse método, pois ele não contém operadores await e executará de forma síncrona.If you build your project at this point, you'll get a warning generated for this method, because it does not contain any await operators and will run synchronously. Ignore isso por enquanto. Adicione os operadores await à medida que você preenche o método.Ignore that for now; you'll add await operators as you fill in the method.

Em seguida, renomeie o namespace definido na instrução namespace, alterando o padrão de ConsoleApp para WebAPIClient.Next, rename the namespace defined in the namespace statement from its default of ConsoleApp to WebAPIClient. Posteriormente, definiremos uma classe repo neste namespace.We'll later define a repo class in this namespace.

Em seguida, atualize o método Main para chamar esse método.Next, update the Main method to call this method. O método ProcessRepositories retorna uma Tarefa, e você não deve sair do programa antes da conclusão dessa tarefa.The ProcessRepositories method returns a Task, and you shouldn't exit the program before that task finishes. Portanto, use o método Wait para bloquear e esperar a conclusão da tarefa:Therefore, you must use the Wait method to block and wait for the task to finish:

static void Main(string[] args)
{
    ProcessRepositories().Wait();
}

Agora, você tem um programa que não faz nada, mas o faz de forma assíncrona.Now, you have a program that does nothing, but does it asynchronously. Vamos melhorar isso.Let's improve it.

Primeiro você precisa de um objeto que é capaz de recuperar dados da Web; você pode usar um HttpClient para fazer isso.First you need an object that is capable to retrieve data from the web; you can use a HttpClient to do that. Esse objeto manipula a solicitação e as respostas.This object handles the request and the responses. Crie uma única instância desse tipo na classe Program dentro do arquivo Program.cs.Instantiate a single instance of that type in the Program class inside the Program.cs file.

namespace WebAPIClient
{
    class Program
    {
        private static readonly HttpClient client = new HttpClient();

        static void Main(string[] args)
        {
            //...
        }
    }
}

Vamos voltar ao método ProcessRepositories e preencher uma primeira versão dele:Let's go back to the ProcessRepositories method and fill in a first version of it:

private static async Task ProcessRepositories()
{
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
    client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");

    var stringTask = client.GetStringAsync("https://api.github.com/orgs/dotnet/repos");

    var msg = await stringTask;
    Console.Write(msg);
}

Também será necessário adicionar duas instruções using novas na parte superior do arquivo para que isso seja compilado:You'll need to also add two new using statements at the top of the file for this to compile:

using System.Net.Http;
using System.Net.Http.Headers;

A primeira versão faz uma solicitação da Web para ler a lista de todos os repositórios na organização dotnet foundation.This first version makes a web request to read the list of all repositories under the dotnet foundation organization. (A ID do gitHub para o .NET Foundation é 'dotnet').(The gitHub ID for the .NET Foundation is 'dotnet'). As primeiras linhas configuram o HttpClient para essa solicitação.The first few lines set up the HttpClient for this request. Primeiro, ele é configurado para aceitar as respostas JSON do GitHub.First, it is configured to accept the GitHub JSON responses. Esse formato é simplesmente JSON.This format is simply JSON. A próxima linha adiciona um cabeçalho de agente do usuário para todas as solicitações deste objeto.The next line adds a User Agent header to all requests from this object. Esses dois cabeçalhos são verificados pelo código do servidor GitHub e são necessários para recuperar informações do GitHub.These two headers are checked by the GitHub server code, and are necessary to retrieve information from GitHub.

Depois de configurar o HttpClient, faça uma solicitação da Web e recupere a resposta.After you've configured the HttpClient, you make a web request and retrieve the response. Nesta primeira versão, você usa o método de conveniência HttpClient.GetStringAsync(String).In this first version, you use the HttpClient.GetStringAsync(String) convenience method. Este método prático inicia uma tarefa que faz a solicitação da Web e, depois, quando a solicitação retornar, ele lê o fluxo de resposta e extrai o conteúdo do fluxo.This convenience method starts a task that makes the web request, and then when the request returns, it reads the response stream and extracts the content from the stream. O corpo da resposta retorna como um String.The body of the response is returned as a String. A cadeia de caracteres fica disponível após a conclusão da tarefa.The string is available when the task completes.

As duas últimas linhas desse método aguardam a tarefa e, depois, imprimem a resposta no console.The final two lines of this method await that task, and then print the response to the console. Compilar o aplicativo e executá-lo.Build the app, and run it. O aviso de compilação desapareceu, pois agora o ProcessRepositories contêm um operador await.The build warning is gone now, because the ProcessRepositories now does contain an await operator. Você verá uma longa exibição do texto formatado em JSON.You'll see a long display of JSON formatted text.

Processar o resultado JSONProcessing the JSON Result

Neste ponto, você já escreveu o código para recuperar uma resposta de um servidor da Web e exibiu o texto contido nessa resposta.At this point, you've written the code to retrieve a response from a web server, and display the text that is contained in that response. Agora, vamos converter essa resposta em JSON em objetos de C#.Next, let's convert that JSON response into C# objects.

O serializador JSON converte os dados em JSON em objetos de C#.The JSON Serializer converts JSON data into C# Objects. A primeira tarefa serve para definir um tipo de classe em C# para conter as informações usadas nessa resposta.Your first task is to define a C# class type to contain the information you use from this response. Vamos compilar isso lentamente, então comece com um tipo C# simples que contém o nome do repositório:Let's build this slowly, so start with a simple C# type that contains the name of the repository:

using System;

namespace WebAPIClient
{
    public class repo
    {
        public string name;
    }
}

Coloque o código acima em um novo arquivo chamado 'repo.cs'.Put the above code in a new file called 'repo.cs'. Esta versão da classe representa o caminho mais simples para processar os dados em JSON.This version of the class represents the simplest path to process JSON data. O nome da classe e o nome do membro corresponderem aos nomes usados no pacote JSON, em vez de seguir as convenções em C#.The class name and the member name match the names used in the JSON packet, instead of following C# conventions. Corrija isso mais tarde fornecendo alguns atributos de configuração.You'll fix that by providing some configuration attributes later. Essa classe demonstra outro recurso importante da serialização e desserialização JSON: Nem todos os campos no pacote JSON fazem parte dessa classe.This class demonstrates another important feature of JSON serialization and deserialization: Not all the fields in the JSON packet are part of this class. O serializador JSON ignorará as informações que não estão incluídas no tipo de classe que está sendo usado.The JSON serializer will ignore information that is not included in the class type being used. Esse recurso facilita a criação de tipos que funcionam apenas com um subconjunto dos campos no pacote JSON.This feature makes it easier to create types that work with only a subset of the fields in the JSON packet.

Agora que você criou o tipo, vamos desserializá-lo.Now that you've created the type, let's deserialize it. Você precisará criar um objeto DataContractJsonSerializer.You'll need to create a DataContractJsonSerializer object. Este objeto deve saber o tipo de CLR esperada para o pacote JSON que ele recupera.This object must know the CLR type expected for the JSON packet it retrieves. O pacote do GitHub contém uma sequência de repositórios, então um List<repo> é o tipo correto.The packet from GitHub contains a sequence of repositories, so a List<repo> is the correct type. Adicione a seguinte linha ao seu método ProcessRepositories:Add the following line to your ProcessRepositories method:

var serializer = new DataContractJsonSerializer(typeof(List<repo>));

Você está usando dois novos namespaces, portanto será necessário adicioná-los também:You're using two new namespaces, so you'll need to add those as well:

using System.Collections.Generic;
using System.Runtime.Serialization.Json;

Em seguida, você usará o serializador para converter JSON em objetos de C#.Next, you'll use the serializer to convert JSON into C# objects. Substitua a chamada para GetStringAsync(String) em seu método ProcessRepositories pelas duas linhas a seguir:Replace the call to GetStringAsync(String) in your ProcessRepositories method with the following two lines:

var streamTask = client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos");
var repositories = serializer.ReadObject(await streamTask) as List<repo>;

Observe que agora você está usando GetStreamAsync(String) em vez de GetStringAsync(String).Notice that you're now using GetStreamAsync(String) instead of GetStringAsync(String). O serializador usa um fluxo, em vez de uma cadeia de caracteres, como sua fonte.The serializer uses a stream instead of a string as its source. Vamos explicar alguns recursos da linguagem C# que estão sendo usados na segunda linha acima.Let's explain a couple features of the C# language that are being used in the second line above. O argumento ReadObject(Stream) é uma expressão await.The argument to ReadObject(Stream) is an await expression. Expressões await podem aparecer em quase todo lugar em seu código, apesar de que até o momento, você apenas as viu como parte de uma instrução de atribuição.Await expressions can appear almost anywhere in your code, even though up to now, you've only seen them as part of an assignment statement.

Em segundo lugar, o operador as converte do tipo de tempo de compilação do object para List<repo>.Secondly, the as operator converts from the compile time type of object to List<repo>. A declaração de ReadObject(Stream) declara que ele retorna um objeto do tipo System.Object.The declaration of ReadObject(Stream) declares that it returns an object of type System.Object. ReadObject(Stream) retornará o tipo especificado no momento da construção (List<repo> neste tutorial).ReadObject(Stream) will return the type you specified when you constructed it (List<repo> in this tutorial). Se a conversão não tiver êxito, o operador as será avaliado com null, em vez de gerar uma exceção.If the conversion does not succeed, the as operator evaluates to null, instead of throwing an exception.

Você está quase terminando esta seção.You're almost done with this section. Agora que você converteu o JSON em objetos C#, vamos exibir o nome de cada repositório.Now that you've converted the JSON to C# objects, let's display the name of each repository. Substitua as linhas que mostram:Replace the lines that read:

var msg = await stringTask;   //**Deleted this
Console.Write(msg);

pelo seguinte:with the following:

foreach (var repo in repositories)
    Console.WriteLine(repo.name);

Compile e execute o aplicativo.Compile and run the application. Ele imprimirá os nomes dos repositórios que fazem parte do .NET Foundation.It will print out the names of the repositories that are part of the .NET Foundation.

Controle da serializaçãoControlling Serialization

Antes de adicionar mais recursos, vamos abordar o tipo repo e fazê-lo seguir convenções mais padrão de C#.Before you add more features, let's address the repo type and make it follow more standard C# conventions. Faça isso anotando a tipo repo com atributos que controlem o modo como o serializador JSON funciona.You'll do this by annotating the repo type with attributes that control how the JSON Serializer works. Em seu caso, você usará esses atributos para definir um mapeamento entre os nomes de chave JSON e os nomes de classe e de membros de C#.In your case, you'll use these attributes to define a mapping between the JSON key names and the C# class and member names. Os dois atributos usados são os atributos DataContractAttribute e DataMemberAttribute.The two attributes used are the DataContractAttribute and DataMemberAttribute attributes. Por convenção, todas as classes de atributo terminam com o sufixo Attribute.By convention, all Attribute classes end in the suffix Attribute. No entanto, não é necessário usar esse sufixo ao aplicar um atributo.However, you do not need to use that suffix when you apply an attribute.

Os atributos DataContractAttribute e DataMemberAttribute são atributos em uma biblioteca diferente, então você precisará adicionar essa biblioteca ao seu arquivo de projeto C# como uma dependência.The DataContractAttribute and DataMemberAttribute attributes are in a different library, so you'll need to add that library to your C# project file as a dependency. Adicione a seguinte linha à seção <ItemGroup> de seu arquivo de projeto:Add the following line to the <ItemGroup> section of your project file:

<PackageReference Include="System.Runtime.Serialization.Primitives" Version="4.3.0" />

Depois de salvar o arquivo, execute dotnet restore (veja a observação) para recuperar esse pacote.After you save the file, run dotnet restore (see note) to retrieve this package.

Em seguida, abra o arquivo repo.cs.Next, open the repo.cs file. Vamos alterar o nome para usar Pascal Case e soletrar o nome Repository completo.Let's change the name to use Pascal Case, and fully spell out the name Repository. Ainda queremos mapear os nós de 'repositório' de JSON para esse tipo, então será necessário adicionar o atributo DataContractAttribute à declaração de classe.We still want to map JSON 'repo' nodes to this type, so you'll need to add the DataContractAttribute attribute to the class declaration. Você definirá a propriedade Name do atributo como o nome de nós de JSON mapeados para esse tipo:You'll set the Name property of the attribute to the name of the JSON nodes that map to this type:

[DataContract(Name="repo")]
public class Repository

O DataContractAttribute é um membro do namespace System.Runtime.Serialization, então você precisará adicionar a instrução using apropriado na parte superior do arquivo:The DataContractAttribute is a member of the System.Runtime.Serialization namespace, so you'll need to add the appropriate using statement at the top of the file:

using System.Runtime.Serialization;

Você alterou o nome da classe repo para Repository, portanto, será necessário fazer a mesma alteração em Program.cs (alguns editores podem oferecer suporte a uma refatoração de renomeação que fará essa alteração automaticamente:)You changed the name of the repo class to Repository, so you'll need to make the same name change in Program.cs (some editors may support a rename refactoring that will make this change automatically:)

var serializer = new DataContractJsonSerializer(typeof(List<Repository>));

// ...

var repositories = serializer.ReadObject(await streamTask) as List<Repository>;

Em seguida, vamos fazer a mesma alteração com o campo name usando a classe DataMemberAttribute.Next, let's make the same change with the name field by using the DataMemberAttribute class. Faça as seguintes alterações na declaração do campo name em repo.cs:Make the following changes to the declaration of the name field in repo.cs:

[DataMember(Name="name")]
public string Name;

Essa alteração significa que você precisa alterar o código que grava o nome de cada repositório em program.cs:This change means you need to change the code that writes the name of each repository in program.cs:

Console.WriteLine(repo.Name);

Faça uma dotnet build seguido por um dotnet run para certificar-se de que você tem os mapeamentos corretos.Do a dotnet build followed by a dotnet run to make sure you've got the mappings correct. Você deve ver o mesmo resultado de antes.You should see the same output as before. Antes, processamos mais propriedades do servidor Web, vamos fazer mais uma alteração na classe Repository.Before we process more properties from the web server, let's make one more change to the Repository class. O membro Name é um campo acessível publicamente.The Name member is a publicly accessible field. Essa não é uma boa prática orientada a objeto, então vamos alterá-lo para uma propriedade.That's not a good object-oriented practice, so let's change it to a property. Para nossos propósitos, não é necessário executar nenhum código específico ao obter ou configurar a propriedade, mas a alteração de uma propriedade facilita a adição dessas alterações posteriormente sem interromper qualquer código que usa a classe Repository.For our purposes, we don't need any specific code to run when getting or setting the property, but changing to a property makes it easier to add those changes later without breaking any code that uses the Repository class.

Remova a definição de campo e substitua-a por uma propriedade autoimplementada:Remove the field definition, and replace it with an auto-implemented property:

public string Name { get; set; }

O compilador gera o corpo dos acessadores get e set, bem como um campo particular para armazenar o nome.The compiler generates the body of the get and set accessors, as well as a private field to store the name. Seria semelhante ao código a seguir, que você pode digitar manualmente:It would be similar to the following code that you could type by hand:

public string Name
{
    get { return this._name; }
    set { this._name = value; }
}
private string _name;

Vamos fazer mais uma alteração antes de adicionar novos recursos.Let's make one more change before adding new features. O método ProcessRepositories pode fazer o trabalho assíncrono e retornar uma coleção de repositórios.The ProcessRepositories method can do the async work and return a collection of the repositories. Vamos retornar o List<Repository> desse método e mover o código que grava as informações no método Main.Let's return the List<Repository> from that method, and move the code that writes the information into the Main method.

Altere a assinatura de ProcessRepositories para retornar uma tarefa cujo resultado é uma lista de objetos Repository:Change the signature of ProcessRepositories to return a task whose result is a list of Repository objects:

private static async Task<List<Repository>> ProcessRepositories()

Depois, basta retornar os repositórios depois de processar a resposta JSON:Then, just return the repositories after processing the JSON response:

var repositories = serializer.ReadObject(await streamTask) as List<Repository>;
return repositories;

O compilador gera o objeto Task<T> para o retorno porque você marcou esse método como async.The compiler generates the Task<T> object for the return because you've marked this method as async. Em seguida, vamos modificar o método Main para que ele capture esses resultados e grave cada nome de repositório no console.Then, let's modify the Main method so that it captures those results and writes each repository name to the console. Seu método Main terá a seguinte aparência:Your Main method now looks like this:

public static void Main(string[] args)
{
    var repositories = ProcessRepositories().Result;

    foreach (var repo in repositories)
        Console.WriteLine(repo.Name);
}

O acesso à propriedade Result de uma Tarefa é bloqueado até que a tarefa seja concluída.Accessing the Result property of a Task blocks until the task has completed. Normalmente, seria preferível await (aguardar) a conclusão da tarefa, como no método ProcessRepositories, mas isso não é permitido no método Main.Normally, you would prefer to await the completion of the task, as in the ProcessRepositories method, but that isn't allowed in the Main method.

Ler mais informaçõesReading More Information

Vamos concluir isso processando mais algumas propriedades no pacote JSON que são enviadas da API do GitHub.Let's finish this by processing a few more of the properties in the JSON packet that gets sent from the GitHub API. Não convém capturar tudo, mas a adição de algumas propriedades demonstrará mais alguns recursos da linguagem C#.You won't want to grab everything, but adding a few properties will demonstrate a few more features of the C# language.

Vamos começar pela adição de alguns tipos mais simples para a definição de classe Repository.Let's start by adding a few more simple types to the Repository class definition. Adicione essas propriedades à classe:Add these properties to that class:

[DataMember(Name="description")]
public string Description { get; set; }

[DataMember(Name="html_url")]
public Uri GitHubHomeUrl { get; set; }

[DataMember(Name="homepage")]
public Uri Homepage { get; set; }

[DataMember(Name="watchers")]
public int Watchers { get; set; }

Essas propriedades têm conversões internas do tipo cadeia de caracteres (que é o que os pacotes JSON contêm) para o tipo de destino.These properties have built-in conversions from the string type (which is what the JSON packets contain) to the target type. O tipo Uri pode ser novidade para você.The Uri type may be new to you. Ele representa um URI, ou, nesse caso, uma URL.It represents a URI, or in this case, a URL. No caso dos tipos Uri e int, se o pacote JSON contiver dados que não são convertidos para o tipo de destino, a ação de serialização lançará uma exceção.In the case of the Uri and int types, if the JSON packet contains data that does not convert to the target type, the serialization action will throw an exception.

Depois de adicioná-los, atualize o método Main para exibir esses elementos:Once you've added these, update the Main method to display those elements:

foreach (var repo in repositories)
{
    Console.WriteLine(repo.Name);
    Console.WriteLine(repo.Description);
    Console.WriteLine(repo.GitHubHomeUrl);
    Console.WriteLine(repo.Homepage);
    Console.WriteLine(repo.Watchers);
    Console.WriteLine();
}

Como etapa final, vamos adicionar as informações para a última operação de envio por push.As a final step, let's add the information for the last push operation. Essas informações são formatadas dessa maneira na resposta JSON:This information is formatted in this fashion in the JSON response:

2016-02-08T21:27:00Z

Esse formato não segue o formato DateTime padrão do .NET.That format does not follow any of the standard .NET DateTime formats. Por isso, você precisará escrever um método de conversão personalizado.Because of that, you'll need to write a custom conversion method. Provavelmente você também não quer expor a cadeia de caracteres bruta aos usuários da classe Repository.You also probably don't want the raw string exposed to users of the Repository class. Os atributos podem ajudar a controlar isto também.Attributes can help control that as well. Primeiro, defina uma propriedade private que conterá a representação de cadeia de caracteres da data e hora em sua classe Repository:First, define a private property that will hold the string representation of the date time in your Repository class:

[DataMember(Name="pushed_at")]
private string JsonDate { get; set; }

O atributo DataMemberAttribute informa ao serializador de que isso deve ser processado, mesmo que não seja um membro público.The DataMemberAttribute attribute informs the serializer that this should be processed, even though it is not a public member. Em seguida, você precisa escrever uma propriedade pública somente leitura que converte a cadeia de caracteres em um objeto DateTime válido, e retorna esse DateTime:Next, you need to write a public read-only property that converts the string to a valid DateTime object, and returns that DateTime:

[IgnoreDataMember]
public DateTime LastPush
{
    get
    {
        return DateTime.ParseExact(JsonDate, "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture);
    }
}

Vamos falar sobre as novas construções acima.Let's go over the new constructs above. O atributo IgnoreDataMember instrui o serializador que esse tipo não deve ser lido para ou gravado de qualquer objeto JSON.The IgnoreDataMember attribute instructs the serializer that this type should not be read to or written from any JSON object. Essa propriedade contém apenas um acessador get.This property contains only a get accessor. Não há nenhum acessador set.There is no set accessor. É assim que você define uma propriedade somente leitura em C#.That's how you define a read-only property in C#. (Sim, você pode criar propriedades somente gravação em C#, mas o valor delas é limitado.) O método ParseExact(String, String, IFormatProvider) analisa uma cadeia de caracteres e cria um objeto DateTime usando um formato de data fornecido e adiciona outros metadados a DateTime usando um objeto CultureInfo.(Yes, you can create write-only properties in C#, but their value is limited.) The ParseExact(String, String, IFormatProvider) method parses a string and creates a DateTime object using a provided date format, and adds additional metadata to the DateTime using a CultureInfo object. Se a operação de análise falhar, o acessador da propriedade gerará uma exceção.If the parse operation fails, the property accessor throws an exception.

Para usar InvariantCulture, você precisará adicionar o namespace System.Globalization às instruções using em repo.cs:To use InvariantCulture, you will need to add the System.Globalization namespace to the using statements in repo.cs:

using System.Globalization;

Por fim, adicione mais uma instrução de saída no console, e você estará pronto para compilar e executar esse aplicativo novamente:Finally, add one more output statement in the console, and you're ready to build and run this app again:

Console.WriteLine(repo.LastPush);

Agora, sua versão deve corresponder ao exemplo finalizado.Your version should now match the finished sample.

ConclusãoConclusion

Este tutorial mostrou como fazer solicitações da Web, analisar o resultados e exibir as propriedades dos resultados.This tutorial showed you how to make web requests, parse the result, and display properties of those results. Você também adicionou novos pacotes como dependências em seu projeto.You've also added new packages as dependencies in your project. Você viu alguns dos recursos da linguagem C# que dão suporte a técnicas orientadas a objeto.You've seen some of the features of the C# language that support object-oriented techniques.

Observação

Começando com o SDK do .NET Core 2.0, não é necessário executar dotnet restore, pois ele é executado implicitamente por todos os comandos que exigem uma restauração, como dotnet new, dotnet build e dotnet run.Starting with .NET Core 2.0 SDK, you don't have to run dotnet restore because it's run implicitly by all commands that require a restore to occur, such as dotnet new, dotnet build and dotnet run. Ainda é um comando válido em determinados cenários em que realizar uma restauração explícita faz sentido, como builds de integração contínua no Azure DevOps Services ou em sistemas de build que precisam controlar explicitamente o horário em que a restauração ocorrerá.It's still a valid command in certain scenarios where doing an explicit restore makes sense, such as continuous integration builds in Azure DevOps Services or in build systems that need to explicitly control the time at which the restore occurs.