Tutorial: Criar e implementar uma aplicação com um serviço de front-end de API Web do ASP.NET Core e um serviço de back-end com monitorização de estadoTutorial: Create and deploy an application with an ASP.NET Core Web API front-end service and a stateful back-end service

Este tutorial é a primeira parte de uma série.This tutorial is part one of a series. Ficará a saber como criar uma aplicação do Azure Service Fabric com um front-end de API Web do ASP.NET Core e um serviço de back-end com monitorização de estado para armazenar dados.You will learn how to create an Azure Service Fabric application with an ASP.NET Core Web API front end and a stateful back-end service to store your data. Quando tiver terminado, terá uma aplicação de votações com um front-end da Web ASP.NET que guarda os resultados das votações num serviço de back-end com estado no cluster.When you're finished, you have a voting application with an ASP.NET Core web front-end that saves voting results in a stateful back-end service in the cluster. Se não quiser criar manualmente a aplicação de voto, pode transferir o código de origem da aplicação concluída e avançar diretamente para o Guia do exemplo de aplicação de voto.If you don't want to manually create the voting application, you can download the source code for the completed application and skip ahead to Walk through the voting sample application. Se preferir, também pode ver um vídeo passo a passo deste tutorial.If you prefer, you can also watch a video walk-through of this tutorial.

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

Na primeira parte da série, saiba como:In part one of the series, you learn how to:

  • Criar um serviço de API Web do ASP.NET Core como um Reliable Service com monitorização de estadoCreate an ASP.NET Core Web API service as a stateful reliable service
  • Criar um serviço de Aplicação Web do ASP.NET Core como um serviço Web sem monitorização de estadoCreate an ASP.NET Core Web Application service as a stateless web service
  • Utilizar o proxy inverso para comunicar com o serviço com estadoUse the reverse proxy to communicate with the stateful service

Nesta série de tutoriais, ficará a saber como:In this tutorial series you learn how to:

Pré-requisitosPrerequisites

Antes de começar este tutorial:Before you begin this tutorial:

Criar um serviço de API Web do ASP.NET como um Reliable ServiceCreate an ASP.NET Web API service as a reliable service

Em primeiro lugar, crie o front-end Web da aplicação de voto com o ASP.NET Core.First, create the web front-end of the voting application using ASP.NET Core. O ASP.NET Core é uma arquitetura de desenvolvimento Web simples para várias plataformas que pode utilizar para criar uma IU Web e APIs Web modernas.ASP.NET Core is a lightweight, cross-platform web development framework that you can use to create modern web UI and web APIs. Para obter uma compreensão abrangente de como o ASP.NET Core se integra com o Service Fabric, recomendamos vivamente que leia o artigo ASP.NET Core no Reliable Services do Service Fabric.To get a complete understanding of how ASP.NET Core integrates with Service Fabric, we strongly recommend reading through the ASP.NET Core in Service Fabric Reliable Services article. Por agora, pode seguir este tutorial para começar a trabalhar rapidamente.For now, you can follow this tutorial to get started quickly. Para saber mais sobre o ASP.NET Core, veja a Documentação do ASP.NET Core.To learn more about ASP.NET Core, see the ASP.NET Core Documentation.

  1. Inicie o Visual Studio como administrador.Launch Visual Studio as an administrator.

  2. Crie um projeto em Ficheiro->Novo->Projeto.Create a project with File->New->Project.

  3. Na caixa de diálogo Novo Projeto, escolha Cloud > Aplicação do Service Fabric.In the New Project dialog, choose Cloud > Service Fabric Application.

  4. Dê o nome Voto à aplicação e clique em OK.Name the application Voting and click OK.

    Caixa de diálogo de novo projeto no Visual Studio

  5. Na página Novo Serviço do Service Fabric, escolha ASP.NET Core Sem Monitorização de Estado e dê o nome VotingWeb ao seu serviço e clique em OK.On the New Service Fabric Service page, choose Stateless ASP.NET Core, name your service VotingWeb, then click OK.

    Escolher o serviço Web do ASP.NET na caixa de diálogo do novo serviço

  6. A página seguinte fornece um conjunto de modelos de projeto do ASP.NET Core.The next page provides a set of ASP.NET Core project templates. Para este tutorial, escolha Aplicação Web (Model-View-Controller) e, em seguida, clique em OK.For this tutorial, choose Web Application (Model-View-Controller), then click OK.

    Escolher o tipo de projeto ASP.NET

    O Visual Studio cria uma aplicação e um projeto de serviço e apresenta-os no Explorador de Soluções.Visual Studio creates an application and a service project and displays them in Solution Explorer.

    Explorador de Soluções após a criação da aplicação com o serviço de API Web do ASP.NET Core

Atualizar o ficheiro site.jsUpdate the site.js file

Abra wwwroot/js/site.js.Open wwwroot/js/site.js. Substitua o respetivo conteúdo pelo seguinte JavaScript utilizado pelas vistas de Início e guarde as alterações.Replace its contents with the following JavaScript used by the Home views, then save your changes.

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 ficheiro Index.cshtmlUpdate the Index.cshtml file

Abra Views/Home/Index.cshtml, a vista específica do controlador Home Page.Open Views/Home/Index.cshtml, the view specific to the Home controller. Substitua o respetivo conteúdo pelo seguinte e, em seguida, guarde as alterações.Replace its contents with the following, then save your changes.

@{
    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 ficheiro _Layout.cshtmlUpdate the _Layout.cshtml file

Abra Views/Shared/_Layout.cshtml, o esquema predefinido da aplicação ASP.NET.Open Views/Shared/_Layout.cshtml, the default layout for the ASP.NET app. Substitua o respetivo conteúdo pelo seguinte e, em seguida, guarde as alterações.Replace its contents with the following, then save your changes.

<!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 ficheiro VotingWeb.csUpdate the VotingWeb.cs file

Abra o ficheiro VotingWeb.cs, o qual cria o WebHost do ASP.NET Core dentro do serviço sem estado através do servidor Web WebListener.Open the VotingWeb.cs file, which creates the ASP.NET Core WebHost inside the stateless service using the WebListener web server.

Adicione a diretiva using System.Net.Http; à parte superior do ficheiro.Add the using System.Net.Http; directive to the top of the file.

Substitua a função CreateServiceInstanceListeners() pelo código seguinte e, em seguida, guarde as alterações.Replace the CreateServiceInstanceListeners() function with the following code, then save your changes.

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();
                    }))
    };
}

Adicione também o seguinte método GetVotingDataServiceName abaixo CreateServiceInstanceListeners() e, em seguida, guarde as alterações.Also add the following GetVotingDataServiceName method below CreateServiceInstanceListeners(), then save your changes. GetVotingDataServiceName devolve o nome do serviço quando consultado.GetVotingDataServiceName returns the service name when polled.

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

Adicionar o ficheiro VotesController.csAdd the VotesController.cs file

Adicione um controlador, o que define as ações de voto.Add a controller, which defines voting actions. Clique com o botão direito do rato na pasta Controladores e, em seguida, selecione Adicionar->Novo item->Visual C#->ASP.NET Core->Classe.Right-click on the Controllers folder, then select Add->New item->Visual C#->ASP.NET Core->Class. Dê ao ficheiro o nome VotesController.cs e clique em Adicionar.Name the file VotesController.cs, then click Add.

Substitua o conteúdo do ficheiro VotesController.cs pelo seguinte e, em seguida, guarde as alterações.Replace the VotesController.cs file contents with the following, then save your changes. Mais adiante, em Atualizar o ficheiro VotesController.cs, este ficheiro é modificado para ler e escrever dados de voto do serviço de back-end.Later, in Update the VotesController.cs file, this file is modified to read and write voting data from the back-end service. Por agora, o controlador devolve dados de cadeia estática à vista.For now, the controller returns static string data to the view.

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 de escutaConfigure the listening port

Quando o serviço de front-end VotingWeb é criado, o Visual Studio seleciona aleatoriamente uma porta na qual o serviço escuta.When the VotingWeb front-end service is created, Visual Studio randomly selects a port for the service to listen on. O serviço VotingWeb atua como front-end desta aplicação e aceita tráfego externo, pelo que vamos vincular este serviço a uma porta fixa e bem conhecida.The VotingWeb service acts as the front-end for this application and accepts external traffic, so let's bind that service to a fixed and well-know port. O manifesto do serviço declara os pontos finais de serviço.The service manifest declares the service endpoints.

No Explorador de Soluções, abra VotingWeb/PackageRoot/ServiceManifest.xml.In Solution Explorer, open VotingWeb/PackageRoot/ServiceManifest.xml. Localize o elemento Ponto Final na secção Recursos e altere o valor de Porta para 8080.Find the Endpoint element in the Resources section and change the Port value to 8080. Para implementar e executar a aplicação localmente, a porta de escuta da aplicação tem de estar aberta e disponível no seu computador.To deploy and run the application locally, the application listening port must be open and available on your computer.

<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>

Também tem de atualizar o valor da propriedade de URL da Aplicação no projeto Voto para que um browser se abra para a porta correta quando depura a sua aplicação.Also update the Application URL property value in the Voting project so a web browser opens to the correct port when you debug your application. No Explorador de Soluções, selecione o projeto Voto e atualize a propriedade URL da Aplicação para 8080.In Solution Explorer, select the Voting project and update the Application URL property to 8080.

Implementar e executar a aplicação de Voto localmenteDeploy and run the Voting application locally

Agora, já pode executar a aplicação de Voto para depuração.You can now go ahead and run the Voting application for debugging. No Visual Studio, prima F5 para implementar a aplicação para o seu cluster do Service Fabric local no modo de depuração.In Visual Studio, press F5 to deploy the application to your local Service Fabric cluster in debug mode. A aplicação irá falhar se, anteriormente, não tiver aberto o Visual Studio como administrador.The application will fail if you didn't previously open Visual Studio as administrator.

Nota

Da primeira vez que executar e implementar a aplicação localmente, o Visual Studio cria um cluster do Service Fabric local para depuração.The first time you run and deploy the application locally, Visual Studio creates a local Service Fabric cluster for debugging. A criação do cluster pode demorar algum tempo.Cluster creation may take some time. O estado da criação do cluster aparece na janela de saída do Visual Studio.The cluster creation status is displayed in the Visual Studio output window.

Depois de implementar a aplicação de Voto no seu cluster do Service Fabric local, a sua aplicação Web irá abrir automaticamente num separador do browser e deve ser semelhante ao seguinte:After the Voting application has been deployed to your local Service Fabric cluster, your web app will open in a browser tab automatically and should look like this:

Front-end do ASP.NET Core

Para parar a depuração da aplicação, volte ao Visual Studio e prima Shift+F5.To stop debugging the application, go back to Visual Studio and press Shift+F5.

Adicionar um serviço de back-end com monitorização de estado à sua aplicaçãoAdd a stateful back-end service to your application

Agora que tem um serviço de API Web do ASP.NET em execução na aplicação, adicione um Reliable Service com monitorização de estado para armazenar alguns dados na aplicação.Now that an ASP.NET Web API service is running in the application, go ahead and add a stateful reliable service to store some data in the application.

O Service Fabric permite-lhe armazenar de forma consistente e fiável os seus dados diretamente dentro do seu serviço através das Reliable Collections.Service Fabric allows you to consistently and reliably store your data right inside your service by using reliable collections. As Reliable Collections são um conjunto de classes de Reliable Collections de elevada disponibilidade que qualquer pessoa que tenha utilizado coleções C# conhecerá.Reliable collections are a set of highly available and reliable collection classes that are familiar to anyone who has used C# collections.

Neste tutorial, irá criar um serviço que armazena um valor de contador numa Reliable Collection.In this tutorial, you create a service which stores a counter value in a reliable collection.

  1. No Explorador de Soluções, clique com o botão direito do rato em Serviços no projeto da aplicação de Voto e escolha Adicionar -> Novo Serviço do Service Fabric... .In Solution Explorer, right-click Services within the Voting application project and choose Add -> New Service Fabric Service....

  2. Na caixa de diálogo Novo Serviço do Service Fabric, escolha ASP.NET Core com Monitorização de Estado e dê ao serviço o nome VotingData e prima OK.In the New Service Fabric Service dialog, choose Stateful ASP.NET Core, name the service VotingData, then press OK.

    Uma vez criado o projeto de serviço, terá dois serviços na sua aplicação.Once your service project is created, you have two services in your application. À medida que continua a criar a sua aplicação, pode adicionar mais serviços com o mesmo método.As you continue to build your application, you can add more services in the same way. Pode dar uma versão e atualizar cada serviço de forma independente.Each can be independently versioned and upgraded.

  3. A página seguinte fornece um conjunto de modelos de projeto do ASP.NET Core.The next page provides a set of ASP.NET Core project templates. Para este tutorial, escolha API.For this tutorial, choose API.

    O Visual Studio cria um projeto de serviço VotingData e apresenta-o no Explorador de Soluções.Visual Studio creates the VotingData service project and displays it in Solution Explorer.

    Explorador de Soluções

Adicionar o ficheiro VoteDataController.csAdd the VoteDataController.cs file

No projeto VotingData, clique com o botão direito do rato na pasta Controladores e, em seguida, selecione Adicionar->Novo item->Classe.In the VotingData project, right-click on the Controllers folder, then select Add->New item->Class. Dê ao ficheiro o nome VoteDataController.cs e clique em Adicionar.Name the file VoteDataController.cs and click Add. Substitua o conteúdo do ficheiro pelo seguinte e, em seguida, guarde as alterações.Replace the file contents with the following, then save your changes.

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();
                }
            }
        }
    }
}

Ligar os serviçosConnect the services

Neste passo, irá ligar os dois serviços e preparar a aplicação Web do front-end para receber e definir informações de voto do serviço de back-end.In this next step, connect the two services and make the front-end Web application get and set voting information from the back-end service.

O Service Fabric garante flexibilidade total na como comunica com o Reliable Services.Service Fabric provides complete flexibility in how you communicate with reliable services. Dentro de uma única aplicação, poderá ter serviços acessíveis através de TCP.Within a single application, you might have services that are accessible via TCP. Outros serviços poderão ser acessíveis através de uma API REST HTTP e outros serviços ainda poderão ser acessíveis através de sockets Web.Other services that might be accessible via an HTTP REST API and still other services could be accessible via web sockets. Para obter informações gerais sobre as opções disponíveis e sobre as desvantagens existentes, veja Comunicar com os serviços.For background on the options available and the tradeoffs involved, see Communicating with services.

Este tutorial utiliza a API Web do ASP.NET Core e o proxy inverso do Service Fabric, para que o serviço Web de front-end VotingWeb possa comunicar com o serviço VotingData de back-end.This tutorial uses ASP.NET Core Web API and the Service Fabric reverse proxy so the VotingWeb front-end web service can communicate with the back-end VotingData service. O proxy inverso está configurado por predefinição para utilizar a porta 19081 e deve funcionar para este tutorial.The reverse proxy is configured by default to use port 19081 and should work for this tutorial. A porta de proxy reverso é definida no modelo de Azure Resource Manager usado para configurar o cluster.The reverse proxy port is set in the Azure Resource Manager template used to set up the cluster. Para encontrar a porta utilizada, procure no modelo de clusters, no recurso Microsoft.ServiceFabric/clusters:To find which port is used, look in the cluster template in the Microsoft.ServiceFabric/clusters resource:

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

Para localizar a porta de proxy reverso usada no seu cluster de desenvolvimento local, exiba o elemento HttpApplicationGatewayEndpoint no manifesto do Cluster Service Fabric local:To find the reverse proxy port used in your local development cluster, view the HttpApplicationGatewayEndpoint element in the local Service Fabric cluster manifest:

  1. Abra uma janela do navegador e navegue até http/:/localhost: 19080 para abrir a ferramenta de Service Fabric Explorer.Open a browser window and navigate to http://localhost:19080 to open the Service Fabric Explorer tool.
  2. Selecione cluster-> manifesto.Select Cluster -> Manifest.
  3. Anote a porta do elemento HttpApplicationGatewayEndpoint.Make a note of the HttpApplicationGatewayEndpoint element port. Por predefinição, esta deve ser 19081.By default this should be 19081. Se não for 19081, terá de alterar a porta no método GetProxyAddress do código VotesController.cs seguinte.If it is not 19081, you will need to change the port in the GetProxyAddress method of the following VotesController.cs code.

Atualizar o ficheiro VotesController.csUpdate the VotesController.cs file

No projeto VotingWeb, abra o ficheiro Controllers/VotesController.cs.In the VotingWeb project, open the Controllers/VotesController.cs file. Substitua o conteúdo da definição de classe VotesController pelo seguinte e, em seguida, guarde as alterações.Replace the VotesController class definition contents with the following, then save your changes. Se a porta do proxy inverso que detetou no passo anterior não for 19081, altere a porta utilizada no método GetProxyAddress de 19081 para a porta que detetou.If the reverse proxy port you discovered in the pervious step is not 19081, change the port used in the GetProxyAddress method from 19081 to the port that you discovered.

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 a aplicação de votação de exemploWalk through the voting sample application

A aplicação de votação é composta por dois serviços:The voting application consists of two services:

  • Serviço de front-end da Web (VotingWeb) - um serviço de front-end da Web ASP.NET Core, que serve a página Web e expõe as APIs da Web para comunicar com o serviço de back-end.Web front-end service (VotingWeb)- An ASP.NET Core web front-end service, which serves the web page and exposes web APIs to communicate with the backend service.
  • Serviço de back-end (VotingData) - um serviço Web ASP.NET Core, que expõe uma API para armazenar os resultados da votação num dicionário fiável que é persistido no disco.Back-end service (VotingData)- An ASP.NET Core web service, which exposes an API to store the vote results in a reliable dictionary persisted on disk.

Diagrama da aplicação

Quando vota na aplicação, ocorrem os seguintes eventos:When you vote in the application the following events occur:

  1. Um JavaScript envia o pedido de voto para a API Web no serviço de front-end Web como pedido HTTP PUT.A JavaScript sends the vote request to the web API in the web front-end service as an HTTP PUT request.

  2. O serviço de front-end da Web utiliza um proxy para localizar e reencaminhar um pedido HTTP PUT para o serviço de back-end.The web front-end service uses a proxy to locate and forward an HTTP PUT request to the back-end service.

  3. O serviço de back-end recebe o pedido de entrada e armazena os resultados atualizados num dicionário fiável, que é replicado para vários nós dentro do cluster e persistido no disco.The back-end service takes the incoming request, and stores the updated result in a reliable dictionary, which gets replicated to multiple nodes within the cluster and persisted on disk. Todos os dados da aplicação são armazenados no cluster, pelo que não é necessária uma base de dados.All the application's data is stored in the cluster, so no database is needed.

Depurar no Visual StudioDebug in Visual Studio

Ao depurar a aplicação no Visual Studio, vai utilizar um cluster de desenvolvimento local do Service Fabric.When debugging application in Visual Studio, you are using a local Service Fabric development cluster. Tem a opção de ajustar a sua experiência de depuração para o seu cenário.You have the option to adjust your debugging experience to your scenario. Nesta aplicação, armazene dados no serviço de back-end através de um dicionário fiável.In this application, store data in the back-end service using a reliable dictionary. O Visual Studio remove a aplicação por predefinição, quando para o depurador.Visual Studio removes the application per default when you stop the debugger. Remover a aplicação faz com que os dados no serviço de back-end sejam também removidos.Removing the application causes the data in the back-end service to also be removed. Para persistir os dados entre as sessões de depuração, pode alterar o Modo de Depuração da Aplicação como propriedade no projeto Voting no Visual Studio.To persist the data between debugging sessions, you can change the Application Debug Mode as a property on the Voting project in Visual Studio.

Para ver o que acontece no código, conclua os passos seguintes:To look at what happens in the code, complete the following steps:

  1. Abra o arquivo VotingWeb\VotesController.cs e defina um ponto de interrupção no método Put da API Web (linha 72).Open the VotingWeb\VotesController.cs file and set a breakpoint in the web API's Put method (line 72).

  2. Abra o arquivo VotingData\VoteDataController.cs e defina um ponto de interrupção no método Put da API Web (linha 54).Open the VotingData\VoteDataController.cs file and set a breakpoint in this web API's Put method (line 54).

  3. Prima F5 para iniciar a aplicação no modo de depuração.Press F5 to start the application in debug mode.

  4. Regresse ao browser e clique numa opção de votação ou adicione uma opção nova.Go back to the browser and click a voting option or add a new voting option. Atingiu o primeiro ponto de interrupção no controlador de API do front-end da Web.You hit the first breakpoint in the web front-end's api controller.

    1. É aqui que o JavaScript no browser envia um pedido para o controlador de API Web no serviço do front-end.This is where the JavaScript in the browser sends a request to the web API controller in the front-end service.

      Adicionar Serviço de Front-End de Votação

    2. Primeiro, construa o URL para o ReverseProxy para o serviço de back-end (1) .First construct the URL to the ReverseProxy for the back-end service (1).

    3. Em seguida, envie o Pedido HTTP PUT para ReverseProxy (2) .Then send the HTTP PUT Request to the ReverseProxy (2).

    4. Por último, devolva a resposta do serviço de back-end ao cliente (3) .Finally the return the response from the back-end service to the client (3).

  5. Prima F5 para continuar.Press F5 to continue.

    1. Está agora no ponto de interrupção do serviço de back-end.You are now at the break point in the back-end service.

      Adicionar Serviço de Back-End de Votação

    2. Na primeira linha no método (1) , utilize o StateManager para obter ou adicionar um dicionário fiável chamado counts.In the first line in the method (1) use the StateManager to get or add a reliable dictionary called counts.

    3. Todas as interações com os valores num dicionário fiável requer uma transação; a utilização da declaração (2) cria essa transação.All interactions with values in a reliable dictionary require a transaction, this using statement (2) creates that transaction.

    4. Na transação, atualize o valor da chave relevante para a opção de voto e consolide a operação (3) .In the transaction, update the value of the relevant key for the voting option and commits the operation (3). Quando é devolvido o método de consolidação, os dados são atualizados no dicionário e replicados para outros nós do cluster.Once the commit method returns, the data is updated in the dictionary and replicated to other nodes in the cluster. Os dados estão agora armazenados em segurança no cluster e o serviço de back-end pode fazer a ativação pós-falha para outros nós, mantendo os dados disponíveis.The data is now safely stored in the cluster, and the back-end service can fail over to other nodes, still having the data available.

  6. Prima F5 para continuar.Press F5 to continue.

Para parar a sessão de depuração, prima Shift + F5.To stop the debugging session, press Shift+F5.

Passos seguintesNext steps

Nesta parte do tutorial, ficou a saber como:In this part of the tutorial, you learned how to:

  • Criar um serviço de API Web do ASP.NET Core como um Reliable Service com monitorização de estadoCreate an ASP.NET Core Web API service as a stateful reliable service
  • Criar um serviço de Aplicação Web do ASP.NET Core como um serviço Web sem monitorização de estadoCreate an ASP.NET Core Web Application service as a stateless web service
  • Utilizar o proxy inverso para comunicar com o serviço com estadoUse the reverse proxy to communicate with the stateful service

Avance para o tutorial seguinte:Advance to the next tutorial: