Tutorial: Criar um aplicativo do Service Fabric .NET

Este tutorial é a primeira parte de uma série. Este tutorial mostra como criar um aplicativo do Azure Service Fabric com um front-end da API Web do ASP.NET Core e um serviço de back-end com estado para armazenar seus dados. Quando terminar, você terá um aplicativo de votação com um front-end da Web do ASP.NET Core que salva os resultados da votação em um serviço de back-end com estado no cluster.

Esta série de tutoriais requer um computador de desenvolvedor do Windows. Se você não quiser criar manualmente o aplicativo de votação, baixe o código-fonte do aplicativo concluído e vá direto para Percorrer o aplicativo de exemplo votação. Você também pode visualizar um passo a passo em vídeo desse tutorial.

Diagrama que mostra um front-end da API AngularJS+ASP.NET conectando-se a um serviço de back-end com estado no Service Fabric.

Neste tutorial, você aprenderá a:

  • Criar um serviço de API Web do ASP.NET Core como um Reliable Services com estado
  • Criar um serviço de Aplicativo Web do ASP.NET Core como um serviço Web sem estado
  • Usar o proxy reverso para se comunicar com o serviço com estado

A série de tutoriais mostra como:

Pré-requisitos

Antes de começar este tutorial:

Criar um serviço de ASP.NET Web API como um serviço confiável

Primeiro, crie o front-end da Web do aplicativo de votação usando o ASP.NET Core. O ASP.NET Core é uma estrutura de desenvolvimento Web leve entre plataformas que permite a criação de uma interface do usuário Web e APIs Web modernas.

Para obter uma compreensão completa de como o ASP.NET Core se integra ao Service Fabric, é altamente recomendável ler o artigo ASP.NET Core nos Reliable Services do Service Fabric. Por hora você pode seguir este tutorial para começar rapidamente. Para saber mais sobre o ASP.NET Core, consulte a Documentação do ASP.NET Core.

Para criar o serviço:

  1. Abra o Visual Studio usando a opção Executar como administrador.

  2. Selecione Arquivo>Novo>Projeto para criar um novo projeto.

  3. Em Criar um novo projeto, selecione Nuvem>Aplicativo do Service Fabric. Selecione Avançar.

    Captura de tela que mostra a caixa de diálogo Criar um novo projeto no Visual Studio.

  4. Selecione ASP.NET Core sem Estado para o novo tipo de projeto, nomeie seu serviço cmo VotingWebe selecione Criar.

    Captura de tela que mostra a escolha de um serviço Web ASP.NET no novo painel de serviço.

  5. A próxima página fornece um conjunto de modelos de projeto do ASP.NET Core. Para este tutorial, selecione Aplicativo Web (Model-View-Controller)e, em seguida, selecione OK.

    Captura de tela que mostra a seleção do tipo de projeto do ASP.NET.

    O Visual Studio cria um aplicativo e um projeto de serviço e os exibe no Gerenciador de Soluções do Visual Studio:

    Captura de tela que mostra o Gerenciador de Soluções depois que o aplicativo é criado usando o serviço de API Web do ASP.NET Core.

Atualizar o arquivo site.js

Acesse wwwroot/js/site.js e abra o arquivo. Substitua o conteúdo do arquivo pelo JavaScript a seguir usado pelas exibições da Página Inicial e salve as alterações.

var app = angular.module('VotingApp', ['ui.bootstrap']);
app.run(function () { });

app.controller('VotingAppController', ['$rootScope', '$scope', '$http', '$timeout', function ($rootScope, $scope, $http, $timeout) {

    $scope.refresh = function () {
        $http.get('api/Votes?c=' + new Date().getTime())
            .then(function (data, status) {
                $scope.votes = data;
            }, function (data, status) {
                $scope.votes = undefined;
            });
    };

    $scope.remove = function (item) {
        $http.delete('api/Votes/' + item)
            .then(function (data, status) {
                $scope.refresh();
            })
    };

    $scope.add = function (item) {
        var fd = new FormData();
        fd.append('item', item);
        $http.put('api/Votes/' + item, fd, {
            transformRequest: angular.identity,
            headers: { 'Content-Type': undefined }
        })
            .then(function (data, status) {
                $scope.refresh();
                $scope.item = undefined;
            })
    };
}]);

Atualizar o arquivo Index.cshtml

Acesse Views/Home/Index.cshtml e abra o arquivo. Esse arquivo tem um modo de exibição específico do controlador Página Inicial. Substitua o conteúdo pelo código a seguir e, em seguida, salve as alterações.

@{
    ViewData["Title"] = "Service Fabric Voting Sample";
}

<div ng-controller="VotingAppController" ng-init="refresh()">
    <div class="container-fluid">
        <div class="row">
            <div class="col-xs-8 col-xs-offset-2 text-center">
                <h2>Service Fabric Voting Sample</h2>
            </div>
        </div>

        <div class="row">
            <div class="col-xs-8 col-xs-offset-2">
                <form class="col-xs-12 center-block">
                    <div class="col-xs-6 form-group">
                        <input id="txtAdd" type="text" class="form-control" placeholder="Add voting option" ng-model="item"/>
                    </div>
                    <button id="btnAdd" class="btn btn-default" ng-click="add(item)">
                        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
                        Add
                    </button>
                </form>
            </div>
        </div>

        <hr/>

        <div class="row">
            <div class="col-xs-8 col-xs-offset-2">
                <div class="row">
                    <div class="col-xs-4">
                        Click to vote
                    </div>
                </div>
                <div class="row top-buffer" ng-repeat="vote in votes.data">
                    <div class="col-xs-8">
                        <button class="btn btn-success text-left btn-block" ng-click="add(vote.Key)">
                            <span class="pull-left">
                                {{vote.key}}
                            </span>
                            <span class="badge pull-right">
                                {{vote.value}} Votes
                            </span>
                        </button>
                    </div>
                    <div class="col-xs-4">
                        <button class="btn btn-danger pull-right btn-block" ng-click="remove(vote.Key)">
                            <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
                            Remove
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Atualizar o arquivo _Layout.cshtml

Acesse Views/Shared/_Layout.cshtml e abra o arquivo. Esse arquivo tem o layout padrão para o aplicativo ASP.NET. Substitua o conteúdo pelo código a seguir e, em seguida, salve as alterações.

<!DOCTYPE html>
<html ng-app="VotingApp" xmlns:ng="https://angularjs.org">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>@ViewData["Title"]</title>

    <link href="~/lib/bootstrap/dist/css/bootstrap.css" rel="stylesheet"/>
    <link href="~/css/site.css" rel="stylesheet"/>

</head>
<body>
<div class="container body-content">
    @RenderBody()
</div>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.2/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.js"></script>
<script src="~/js/site.js"></script>

@RenderSection("Scripts", required: false)
</body>
</html>

Atualizar o arquivo VotaçãoWeb.cs

Abra o arquivo VotingWeb.cs. Esse arquivo cria o WebHost do ASP.NET Core dentro do serviço sem estado usando o servidor Web WebListener.

No início do arquivo, adicione a diretiva using System.Net.Http;.

Substitua a função CreateServiceInstanceListeners() pelo código a seguir, depois salve as alterações.

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(
            serviceContext =>
                new KestrelCommunicationListener(
                    serviceContext,
                    "ServiceEndpoint",
                    (url, listener) =>
                    {
                        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                        return new WebHostBuilder()
                            .UseKestrel()
                            .ConfigureServices(
                                services => services
                                    .AddSingleton<HttpClient>(new HttpClient())
                                    .AddSingleton<FabricClient>(new FabricClient())
                                    .AddSingleton<StatelessServiceContext>(serviceContext))
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseStartup<Startup>()
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                            .UseUrls(url)
                            .Build();
                    }))
    };
}

Em seguida, adicione o método GetVotingDataServiceName a seguir após o CreateServiceInstanceListeners() e salve as alterações. GetVotingDataServiceName retorna o nome do serviço quando sondado.

internal static Uri GetVotingDataServiceName(ServiceContext context)
{
    return new Uri($"{context.CodePackageActivationContext.ApplicationName}/VotingData");
}

Adicionar o arquivo VotesController.cs

Adicione um controlador para definir ações de votação. Clique com o botão direito do mouse na pasta Controladores e selecione Adicionar>Novo item>Visual C#>ASP.NET Core>Classe. Nomeie o arquivo como VotesController.cse selecione Adicionar.

Substitua o conteúdo do arquivo VotesController.cs pelo código a seguir, depois salve as alterações. Posteriormente, em Atualizar o arquivo VotesController.cs, esse arquivo é modificado para ler e gravar dados de votação do serviço de back-end. Por enquanto, o controlador retorna dados de cadeia de caracteres estática para a exibição.

namespace VotingWeb.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Fabric;
    using System.Fabric.Query;
    using System.Linq;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json;

    [Produces("application/json")]
    [Route("api/Votes")]
    public class VotesController : Controller
    {
        private readonly HttpClient httpClient;

        public VotesController(HttpClient httpClient)
        {
            this.httpClient = httpClient;
        }

        // GET: api/Votes
        [HttpGet]
        public async Task<IActionResult> Get()
        {
            List<KeyValuePair<string, int>> votes= new List<KeyValuePair<string, int>>();
            votes.Add(new KeyValuePair<string, int>("Pizza", 3));
            votes.Add(new KeyValuePair<string, int>("Ice cream", 4));

            return Json(votes);
        }
     }
}

Configurar a porta ouvinte

Quando o serviço de front-end VotingWeb é criado, o Visual Studio seleciona aleatoriamente uma porta para o serviço ao escutar em. O serviço VotingWeb atua como o front-end desse aplicativo e aceita o tráfego externo. Nesta seção, você associa esse serviço a uma porta fixa e conhecida. O manifesto do serviço declara os pontos de extremidade de serviço.

No Gerenciador de Soluções, abra VotingWeb/PackageRoot/ServiceManifest.xml. Na seção Resources, localize o elemento Endpoint e altere o valor Port para 8080.

Para implantar e executar o aplicativo localmente, a porta de escuta do aplicativo deve estar aberta e disponível no computador.

<Resources>
    <Endpoints>
      <!-- This endpoint is used by the communication listener to obtain the port on which to 
           listen. Please note that if your service is partitioned, this port is shared with 
           replicas of different partitions that are placed in your code. -->
      <Endpoint Protocol="http" Name="ServiceEndpoint" Type="Input" Port="8080" />
    </Endpoints>
  </Resources>

Atualize também o valor da propriedade Application URL no projeto de Votação para que um navegador Web abra a porta correta ao depurar o seu aplicativo. No Gerenciador de Soluções, selecione o projeto Votação e atualize a propriedade Application URL para 8080.

Implantar e executar o aplicativo de Votação localmente

Agora você pode executar o aplicativo de votação para depurá-lo. No Visual Studio, pressione F5 para implantar o aplicativo no cluster do Service Fabric local no modo de depuração. O aplicativo falhará se você não abriu anteriormente o Visual Studio usando a opção Executar como administrador.

Observação

Na primeira vez em que você executar e implantar o aplicativo localmente, o Visual Studio criará um cluster do Service Fabric local para depuração. O processo para criar um cluster pode levar algum tempo. O status de criação do cluster é exibido na janela de saída do Visual Studio.

Depois que o aplicativo de votação é implantado no cluster local do Service Fabric, seu aplicativo Web é aberto automaticamente em uma guia do navegador. Ele é semelhante a este exemplo:

Captura de tela que mostra o front-end do aplicativo em um navegador.

Para interromper a depuração do aplicativo, volte para o Visual Studio e selecione Shift + F5.

Adicionar um serviço de back-end com estado ao seu aplicativo

Agora que um serviço de ASP.NET Web API está em execução no aplicativo, vamos prosseguir e adicionar um serviço confiável com estado para armazenar alguns dados no aplicativo.

O Service Fabric permite que você armazene seus dados de forma consistente e confiável diretamente em seu serviço usando as coleções confiáveis. As coleções confiáveis são um conjunto de classes de coleção confiáveis altamente disponíveis que são familiares a todos aqueles que já usaram coleções de C#.

Para criar um serviço que armazena um valor de contador em uma coleção confiável:

  1. No Gerenciador de Soluções, clique com o botão direito do mouse em Serviços no projeto do aplicativo de Votação e escolha Adicionar>Novo Serviço do Fabric Service.

  2. Na caixa de diálogo Novo Serviço do Service Fabric, selecione ASP.NET Core com Estado, nomeie o serviço como VotingData e selecioneOK.

    Depois de criar seu projeto de serviço, você terá dois serviços em seu aplicativo. À medida que você continua a construir seu aplicativo, você pode adicionar mais serviços da mesma maneira. Cada serviço pode ser implantado independentemente e ter seu próprio controle de versão.

  3. A próxima página fornece um conjunto de modelos de projeto do ASP.NET Core. Para este tutorial, selecione API.

    O Visual Studio cria um projeto de serviço VotingData e o exibe no Gerenciador de Soluções:

    Captura de tela que mostra o projeto de serviço VotingData no Gerenciador de Soluções.

Adicionar o arquivo VoteDataController.cs

No projeto VotingData, clique com o botão direito do mouse na pasta Controladores e selecione Adicionar>Nova item>Classe. Nomeie o arquivo como VoteDataController.cs e clique em Adicionar. Substitua o conteúdo do arquivo pelo código a seguir, depois salve as alterações.

namespace VotingData.Controllers
{
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.ServiceFabric.Data;
    using Microsoft.ServiceFabric.Data.Collections;

    [Route("api/[controller]")]
    public class VoteDataController : Controller
    {
        private readonly IReliableStateManager stateManager;

        public VoteDataController(IReliableStateManager stateManager)
        {
            this.stateManager = stateManager;
        }

        // GET api/VoteData
        [HttpGet]
        public async Task<IActionResult> Get()
        {
            CancellationToken ct = new CancellationToken();

            IReliableDictionary<string, int> votesDictionary = await this.stateManager.GetOrAddAsync<IReliableDictionary<string, int>>("counts");

            using (ITransaction tx = this.stateManager.CreateTransaction())
            {
                Microsoft.ServiceFabric.Data.IAsyncEnumerable<KeyValuePair<string, int>> list = await votesDictionary.CreateEnumerableAsync(tx);

                Microsoft.ServiceFabric.Data.IAsyncEnumerator<KeyValuePair<string, int>> enumerator = list.GetAsyncEnumerator();

                List<KeyValuePair<string, int>> result = new List<KeyValuePair<string, int>>();

                while (await enumerator.MoveNextAsync(ct))
                {
                    result.Add(enumerator.Current);
                }

                return this.Json(result);
            }
        }

        // PUT api/VoteData/name
        [HttpPut("{name}")]
        public async Task<IActionResult> Put(string name)
        {
            IReliableDictionary<string, int> votesDictionary = await this.stateManager.GetOrAddAsync<IReliableDictionary<string, int>>("counts");

            using (ITransaction tx = this.stateManager.CreateTransaction())
            {
                await votesDictionary.AddOrUpdateAsync(tx, name, 1, (key, oldvalue) => oldvalue + 1);
                await tx.CommitAsync();
            }

            return new OkResult();
        }

        // DELETE api/VoteData/name
        [HttpDelete("{name}")]
        public async Task<IActionResult> Delete(string name)
        {
            IReliableDictionary<string, int> votesDictionary = await this.stateManager.GetOrAddAsync<IReliableDictionary<string, int>>("counts");

            using (ITransaction tx = this.stateManager.CreateTransaction())
            {
                if (await votesDictionary.ContainsKeyAsync(tx, name))
                {
                    await votesDictionary.TryRemoveAsync(tx, name);
                    await tx.CommitAsync();
                    return new OkResult();
                }
                else
                {
                    return new NotFoundResult();
                }
            }
        }
    }
}

Conectar os serviços

Nesta seção, você conectará dois serviços. Você faz com que o aplicativo Web front-end obtenha informações de votação do serviço de back-end e defina as informações no aplicativo.

O Service Fabric oferece flexibilidade completa na maneira como você se comunica com serviços confiáveis. Em um único aplicativo, você pode ter serviços acessíveis por meio de TCP/IP, por meio de uma API REST HTTP ou por meio do protocolo WebSocket. Para saber mais sobre as opções disponíveis e as compensações envolvidas, consulte Comunicação com os serviços.

Este tutorial usa a API da Web do ASP.NET Core e o Proxy reverso do Service Fabric de forma que o serviço Web de front-end VotingWeb possa se comunicar com o serviço de back-end VotingData. Um proxy reverso é configurado por padrão para usar a porta 19081. A porta de proxy reverso é definida no modelo do Azure Resource Manager usado para configurar o cluster. Para localizar qual porta é usada, examine o modelo de cluster no recurso Microsoft.ServiceFabric/clusters:

"nodeTypes": [
          {
            ...
            "httpGatewayEndpointPort": "[variables('nt0fabricHttpGatewayPort')]",
            "isPrimary": true,
            "vmInstanceCount": "[parameters('nt0InstanceCount')]",
            "reverseProxyEndpointPort": "[parameters('SFReverseProxyPort')]"
          }
        ],

Para encontrar a porta de proxy reverso usada no cluster de desenvolvimento local, exiba o elemento HttpApplicationGatewayEndpoint no manifesto do cluster do Service Fabric local:

  1. Para abrir a ferramenta Service Fabric Explorer, abra um navegador e vá para http://localhost:19080.
  2. Selecione Cluster>Manifesto.
  3. Anote a porta do elemento HttpApplicationGatewayEndpoint. Por padrão, a porta é a 19081. Se não for 19081, altere a porta no método GetProxyAddress do código VotesController.cs conforme descrito na próxima seção.

Atualizar o arquivo VotesController.cs

No projeto VotingWeb, abra o arquivo Controllers/VotesController.cs. Substitua o conteúdo de definição de classe VotesController pelo código a seguir, depois salve as alterações. Se a porta de proxy reverso que você descobriu na etapa anterior não for 19081, altere a porta no método GetProxyAddress de 19081 para a porta que você descobriu.

public class VotesController : Controller
{
    private readonly HttpClient httpClient;
    private readonly FabricClient fabricClient;
    private readonly StatelessServiceContext serviceContext;

    public VotesController(HttpClient httpClient, StatelessServiceContext context, FabricClient fabricClient)
    {
        this.fabricClient = fabricClient;
        this.httpClient = httpClient;
        this.serviceContext = context;
    }

    // GET: api/Votes
    [HttpGet("")]
    public async Task<IActionResult> Get()
    {
        Uri serviceName = VotingWeb.GetVotingDataServiceName(this.serviceContext);
        Uri proxyAddress = this.GetProxyAddress(serviceName);

        ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceName);

        List<KeyValuePair<string, int>> result = new List<KeyValuePair<string, int>>();

        foreach (Partition partition in partitions)
        {
            string proxyUrl =
                $"{proxyAddress}/api/VoteData?PartitionKey={((Int64RangePartitionInformation) partition.PartitionInformation).LowKey}&PartitionKind=Int64Range";

            using (HttpResponseMessage response = await this.httpClient.GetAsync(proxyUrl))
            {
                if (response.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    continue;
                }

                result.AddRange(JsonConvert.DeserializeObject<List<KeyValuePair<string, int>>>(await response.Content.ReadAsStringAsync()));
            }
        }

        return this.Json(result);
    }

    // PUT: api/Votes/name
    [HttpPut("{name}")]
    public async Task<IActionResult> Put(string name)
    {
        Uri serviceName = VotingWeb.GetVotingDataServiceName(this.serviceContext);
        Uri proxyAddress = this.GetProxyAddress(serviceName);
        long partitionKey = this.GetPartitionKey(name);
        string proxyUrl = $"{proxyAddress}/api/VoteData/{name}?PartitionKey={partitionKey}&PartitionKind=Int64Range";

        StringContent putContent = new StringContent($"{{ 'name' : '{name}' }}", Encoding.UTF8, "application/json");
        putContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

        using (HttpResponseMessage response = await this.httpClient.PutAsync(proxyUrl, putContent))
        {
            return new ContentResult()
            {
                StatusCode = (int) response.StatusCode,
                Content = await response.Content.ReadAsStringAsync()
            };
        }
    }

    // DELETE: api/Votes/name
    [HttpDelete("{name}")]
    public async Task<IActionResult> Delete(string name)
    {
        Uri serviceName = VotingWeb.GetVotingDataServiceName(this.serviceContext);
        Uri proxyAddress = this.GetProxyAddress(serviceName);
        long partitionKey = this.GetPartitionKey(name);
        string proxyUrl = $"{proxyAddress}/api/VoteData/{name}?PartitionKey={partitionKey}&PartitionKind=Int64Range";

        using (HttpResponseMessage response = await this.httpClient.DeleteAsync(proxyUrl))
        {
            if (response.StatusCode != System.Net.HttpStatusCode.OK)
            {
                return this.StatusCode((int) response.StatusCode);
            }
        }

        return new OkResult();
    }


    /// <summary>
    /// Constructs a reverse proxy URL for a given service.
    /// Example: http://localhost:19081/VotingApplication/VotingData/
    /// </summary>
    /// <param name="serviceName"></param>
    /// <returns></returns>
    private Uri GetProxyAddress(Uri serviceName)
    {
        return new Uri($"http://localhost:19081{serviceName.AbsolutePath}");
    }

    /// <summary>
    /// Creates a partition key from the given name.
    /// Uses the zero-based numeric position in the alphabet of the first letter of the name (0-25).
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    private long GetPartitionKey(string name)
    {
        return Char.ToUpper(name.First()) - 'A';
    }
}

Percorrer o aplicativo de exemplo de votação

O aplicativo de votação consiste em dois serviços:

  • Um serviço de front-end da Web (VotingWeb): um serviço de front-end da Web do ASP.NET Core, que fornece a página da Web e expõe APIs Web para se comunicar com o serviço de back-end.
  • Um serviço de back-end (VotingData): um serviço Web do ASP.NET Core, que expõe uma API para armazenar os resultados da votação em um dicionário confiável persistido em disco.

Diagrama que ilustra os serviços de aplicativo.

Quando você vota no aplicativo, os seguintes eventos ocorrem:

  1. Um arquivo JavaScript envia a solicitação de votação para a API Web no serviço de front-end da Web como uma solicitação HTTP PUT.

  2. O serviço de front-end da Web usa um proxy para localizar e encaminhar uma solicitação HTTP PUT para o serviço de back-end.

  3. O serviço de back-end aceita a solicitação de entrada e armazena o resultado atualizado em um dicionário confiável. O dicionário é replicado para vários nós no cluster e persistido no disco. Todos os dados do aplicativo são armazenados no cluster e, portanto, nenhum banco de dados é necessário.

Depuração no Visual Studio

Ao depurar um aplicativo no Visual Studio, você usa um cluster de desenvolvimento local do Service Fabric. Você pode ajustar sua experiência de depuração para seu cenário.

Neste aplicativo, armazene os dados no serviço de back-end, usando um dicionário confiável. O Visual Studio remove o aplicativo por padrão quando você interrompe o depurador. A remoção do aplicativo faz com que os dados no serviço de back-end também sejam removidos. Para persistir os dados entre as sessões de depuração, altere o Modo de Depuração de Aplicativo como uma propriedade no projeto Votação do Visual Studio.

Para ver o que acontece no código, conclua as seguintes etapas:

  1. Abra o arquivo VotingWeb\VotesController.cs e defina um ponto de interrupção no método Put da API Web (linha 72).

  2. Abra o arquivo VotingData\VoteDataController.cs e defina um ponto de interrupção no método Put dessa API Web (linha 54).

  3. Selecione F5 para iniciar o aplicativo no modo de depuração.

  4. Volte para o navegador e clique em uma opção de votação ou adicione uma nova opção de votação. Você chegou ao primeiro ponto de interrupção no controlador de API do front-end da Web.

    Esse é o local em que o JavaScript no navegador envia uma solicitação para o controlador da API Web no serviço de front-end:

    Captura de tela que mostra a adição de um serviço de front-end de votação.

    1. Primeiro, construa a URL para o proxy reverso no serviço de back-end. (1)
    2. Em seguida, envie a solicitação PUT HTTP para o proxy reverso. (2)
    3. Por fim, retorne a resposta do serviço de back-end para o cliente. (3)
  5. Selecione F5 para continuar.

    Agora você está no ponto de interrupção no serviço de back-end:

    Captura de tela que mostra a adição de uma votação ao serviço de back-end.

    1. Na primeira linha do método stateManager, use para obter ou adicionar um dicionário confiável chamado counts. (1)
    2. Todas as interações que têm valores em um dicionário confiável exigem uma transação. Essa instrução using cria essa transação. (2)
    3. Na transação, atualize o valor da chave relevante para a opção de votação e confirme a operação. Quando o método commit retorna, os dados são atualizados no dicionário. Em seguida, ele é replicado para outros nós no cluster. Os dados agora estão armazenados com segurança no cluster e o serviço de back-end pode fazer failover para outros nós e ainda ter os dados disponíveis. (3)
  6. Selecione F5 para continuar.

Para interromper a sessão de depuração, selecione Shift + F5.

Próxima etapa

Prosseguir para o próximo tutorial: