Esercitazione: Creare e distribuire un'applicazione con un servizio front-end API Web ASP.NET Core e un servizio back-end con statoTutorial: Create and deploy an application with an ASP.NET Core Web API front-end service and a stateful back-end service

Questa è la prima di una serie di esercitazioni.This tutorial is part one of a series. Illustra come creare un'applicazione di Azure Service Fabric con un front-end API Web ASP.NET Core e un servizio back-end con stato per archiviare i dati.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. Al termine, sarà disponibile un'applicazione di voto con un front-end Web ASP.NET Core che salva i risultati delle votazioni in un servizio back-end con stato nel 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 non si vuole creare manualmente l'applicazione di voto, è possibile scaricare il codice sorgente per l'applicazione completata e passare direttamente alla Descrizione dettagliata dell'applicazione di voto di esempio.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 si preferisce, è anche possibile guardare una procedura dettagliata video di questa esercitazione.If you prefer, you can also watch a video walk-through of this tutorial.

Diagramma dell'applicazione

Nella prima parte della serie si apprenderà come:In part one of the series, you learn how to:

  • Creare un servizio API Web ASP.NET Core come servizio Reliable con statoCreate an ASP.NET Core Web API service as a stateful reliable service
  • Creare un servizio applicazione Web ASP.NET Core come servizio Web senza statoCreate an ASP.NET Core Web Application service as a stateless web service
  • Usare il proxy inverso per comunicare con il servizio con statoUse the reverse proxy to communicate with the stateful service

In questa serie di esercitazioni si apprenderà come:In this tutorial series you learn how to:

PrerequisitiPrerequisites

Prima di iniziare questa esercitazione:Before you begin this tutorial:

Creare un servizio API Web ASP.NET come servizio ReliableCreate an ASP.NET Web API service as a reliable service

Per prima cosa, creare il front-end Web dell'applicazione di voto usando ASP.NET Core.First, create the web front-end of the voting application using ASP.NET Core. ASP.NET Core è un framework di sviluppo Web multipiattaforma leggero, che consente di creare un'interfaccia utente Web e API Web moderne.ASP.NET Core is a lightweight, cross-platform web development framework that you can use to create modern web UI and web APIs. Per comprendere a fondo la modalità di integrazione di ASP.NET Core con Service Fabric, si consiglia di leggere l'articolo ASP.NET Core in Reliable Services di 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. Per il momento, è possibile seguire questa esercitazione per essere subito operativi.For now, you can follow this tutorial to get started quickly. Per altre informazioni su ASP.NET Core, vedere la documentazione di ASP.NET Core.To learn more about ASP.NET Core, see the ASP.NET Core Documentation.

  1. Avviare Visual Studio come amministratore.Launch Visual Studio as an administrator.

  2. Creare un progetto da File->Nuovo->Progetto.Create a project with File->New->Project.

  3. Nella finestra di dialogo Nuovo progetto scegliere Cloud > Applicazione di Service Fabric.In the New Project dialog, choose Cloud > Service Fabric Application.

  4. Assegnare all'applicazione il nome Voting e fare clic su OK.Name the application Voting and click OK.

    Finestra di dialogo Nuovo progetto in Visual Studio

  5. Nella pagina Nuovo servizio Service Fabric scegliere ASP.NET Core senza stato, assegnare al servizio il nome VotingWeb e fare clic su OK.On the New Service Fabric Service page, choose Stateless ASP.NET Core, name your service VotingWeb, then click OK.

    Scelta di un servizio Web ASP.NET nella finestra di dialogo del nuovo servizio

  6. Nella pagina successiva è disponibile un set di modelli di progetto ASP.NET Core.The next page provides a set of ASP.NET Core project templates. Per questa esercitazione scegliere Applicazione Web (MVC) e fare clic su OK.For this tutorial, choose Web Application (Model-View-Controller), then click OK.

    Scegliere un tipo di progetto ASP.NET

    Visual Studio crea un'applicazione e un progetto di servizio e li visualizza in Esplora soluzioni.Visual Studio creates an application and a service project and displays them in Solution Explorer.

    Esplora soluzioni dopo la creazione dell'applicazione con il servizio API Web ASP.NET Core

Aggiornare il file site.jsUpdate the site.js file

Aprire wwwroot/js/site.js.Open wwwroot/js/site.js. Sostituirne il contenuto con il codice JavaScript seguente usato dalle visualizzazioni Home e salvare le modifiche apportate.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;
            })
    };
}]);

Aggiornare il file Index.cshtmlUpdate the Index.cshtml file

Aprire Views/Home/Index.cshtml, ovvero la visualizzazione specifica del controller Home.Open Views/Home/Index.cshtml, the view specific to the Home controller. Sostituirne il contenuto con il codice seguente e quindi salvare le modifiche.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>

Aggiornare il file _Layout.cshtmlUpdate the _Layout.cshtml file

Aprire Views/Shared/_Layout.cshtml, ovvero il layout predefinito per l'app ASP.NET.Open Views/Shared/_Layout.cshtml, the default layout for the ASP.NET app. Sostituirne il contenuto con il codice seguente e quindi salvare le modifiche.Replace its contents with the following, then save your changes.

<!DOCTYPE html>
<html ng-app="VotingApp" xmlns:ng="http://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>

Aggiornare il file VotingWeb.csUpdate the VotingWeb.cs file

Aprire il file VotingWeb.cs, che crea il WebHost ASP.NET Core all'interno del servizio senza stato tramite il server Web WebListener.Open the VotingWeb.cs file, which creates the ASP.NET Core WebHost inside the stateless service using the WebListener web server.

Aggiungere la direttiva using System.Net.Http; all'inizio del file.Add the using System.Net.Http; directive to the top of the file.

Sostituire la funzione CreateServiceInstanceListeners() con il codice seguente e salvare le modifiche.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();
                    }))
    };
}

Aggiungere anche il metodo GetVotingDataServiceName seguente sotto a CreateServiceInstanceListeners() e salvare le modifiche.Also add the following GetVotingDataServiceName method below CreateServiceInstanceListeners(), then save your changes. GetVotingDataServiceName restituisce il nome del servizio quando viene eseguito il polling.GetVotingDataServiceName returns the service name when polled.

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

Aggiungere il file VotesController.csAdd the VotesController.cs file

Aggiungere un controller che definisce le azioni di voto.Add a controller, which defines voting actions. Fare clic con il pulsante destro del mouse sulla cartella Controller e selezionare Aggiungi->Nuovo elemento->Visual C#->ASP.NET Core->Classe.Right-click on the Controllers folder, then select Add->New item->Visual C#->ASP.NET Core->Class. Assegnare al file il nome VotesController.cs e fare clic su Aggiungi.Name the file VotesController.cs, then click Add.

Sostituire il contenuto del file VotesController.cs con il codice seguente e salvare le modifiche.Replace the VotesController.cs file contents with the following, then save your changes. Nella sezione Aggiornare il file VotesController.cs disponibile più avanti, questo file viene modificato per leggere e scrivere i dati di voto dal servizio back-end.Later, in Update the VotesController.cs file, this file is modified to read and write voting data from the back-end service. Per il momento, il controller restituisce nella visualizzazione i dati di una stringa statica.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);
        }
     }
}

Configurare la porta di ascoltoConfigure the listening port

Quando viene creato il servizio front-end VotingWeb, Visual Studio seleziona casualmente una porta su cui il servizio resterà in ascolto.When the VotingWeb front-end service is created, Visual Studio randomly selects a port for the service to listen on. Poiché il servizio VotingWeb agisce come front-end per l'applicazione e accetta traffico esterno, è opportuno associare il servizio a una porta fissa e conosciuta.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. Il manifesto del servizio dichiara gli endpoint di servizio.The service manifest declares the service endpoints.

In Esplora soluzioni aprire VotingWeb/PackageRoot/ServiceManifest.xml.In Solution Explorer, open VotingWeb/PackageRoot/ServiceManifest.xml. Trovare l'elemento Endpoint nella sezione Risorse e modificare il valore della Porta impostandolo su 8080.Find the Endpoint element in the Resources section and change the Port value to 8080. Per distribuire ed eseguire l'applicazione in locale, la porta dell'applicazione in ascolto deve essere aperta e disponibile nel computer.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>

Aggiornare anche il valore della proprietà URL applicazione nel progetto Voting in modo che, quando si esegue il debug dell'applicazione, un Web browser si apra sulla porta corretta.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. In Esplora soluzioni selezionare il progetto Voting e aggiornare la proprietà URL applicazione impostandola su 8080.In Solution Explorer, select the Voting project and update the Application URL property to 8080.

URL applicazione

Distribuire ed eseguire l'applicazione Voting in localeDeploy and run the Voting application locally

È ora possibile andare avanti con l'esercitazione ed eseguire il debug dell'applicazione Voting.You can now go ahead and run the Voting application for debugging. In Visual Studio premere F5 per distribuire l'applicazione nel cluster di Service Fabric locale in modalità di debug.In Visual Studio, press F5 to deploy the application to your local Service Fabric cluster in debug mode. L'applicazione ha esito negativo se in precedenza Visual Studio non è stato aperto come amministratore.The application will fail if you didn't previously open Visual Studio as administrator.

Nota

La prima volta che si esegue e si distribuisce l'applicazione in locale, Visual Studio crea un cluster di Service Fabric locale per il debug.The first time you run and deploy the application locally, Visual Studio creates a local Service Fabric cluster for debugging. La creazione del cluster può richiedere del tempo.Cluster creation may take some time. Lo stato della creazione del cluster verrà visualizzato nella finestra di output di Visual Studio.The cluster creation status is displayed in the Visual Studio output window.

Dopo aver distribuito l'applicazione Voting nel cluster di Service Fabric locale, l'app Web si apre automaticamente in una scheda del browser e dovrebbe avere un aspetto simile al seguente: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 ASP.NET Core

Per arrestare il debug dell'applicazione, tornare a Visual Studio e premere MAIUSC+F5.To stop debugging the application, go back to Visual Studio and press Shift+F5.

Aggiungere un servizio back-end con stato a un'applicazioneAdd a stateful back-end service to your application

Ora che è presente un servizio API Web ASP.NET in esecuzione nell'applicazione, aggiungere un servizio Reliable con stato per archiviare alcuni dati nell'applicazione.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.

Service Fabric consente di archiviare in modo coerente e affidabile i dati all'interno del servizio usando raccolte Reliable Collections.Service Fabric allows you to consistently and reliably store your data right inside your service by using reliable collections. Le Reliable Collection sono un set di classi di raccolte con elevati livelli di disponibilità e affidabilità che risultano familiari a chiunque abbia usato raccolte C#.Reliable collections are a set of highly available and reliable collection classes that are familiar to anyone who has used C# collections.

In questa esercitazione si creerà un servizio che archivia un valore del contatore in una Reliable Collection.In this tutorial, you create a service which stores a counter value in a reliable collection.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse su Servizi nel progetto dell'applicazione Voting e scegliere Aggiungi -> Nuovo servizio Service Fabric.In Solution Explorer, right-click Services within the Voting application project and choose Add -> New Service Fabric Service....

  2. Nella finestra di dialogo Nuovo servizio Service Fabric scegliere ASP.NET Core con stato, assegnare al servizio il nome VotingData e premere OK.In the New Service Fabric Service dialog, choose Stateful ASP.NET Core, name the service VotingData, then press OK.

    Una volta creato il progetto di servizio, l'applicazione includerà due servizi.Once your service project is created, you have two services in your application. Man mano che si compila l'applicazione, è possibile aggiungere altri servizi nello stesso modo.As you continue to build your application, you can add more services in the same way. Per ogni servizio, sarà possibile eseguire in modo indipendente il controllo della versione e l'aggiornamento.Each can be independently versioned and upgraded.

  3. Nella pagina successiva è disponibile un set di modelli di progetto ASP.NET Core.The next page provides a set of ASP.NET Core project templates. Per questa esercitazione, scegliere API.For this tutorial, choose API.

    Visual Studio crea un progetto di servizio VotingData e lo visualizza in Esplora soluzioni.Visual Studio creates the VotingData service project and displays it in Solution Explorer.

    Esplora soluzioni

Aggiungere il file VoteDataController.csAdd the VoteDataController.cs file

Nel progetto VotingData fare clic con il pulsante destro del mouse sulla cartella Controller e selezionare Aggiungi->Nuovo elemento->Classe.In the VotingData project, right-click on the Controllers folder, then select Add->New item->Class. Assegnare al file il nome VoteDataController.cs e fare clic su Aggiungi.Name the file VoteDataController.cs and click Add. Sostituire il contenuto del file con il codice seguente e quindi salvare le modifiche.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();
                }
            }
        }
    }
}

Connettere i serviziConnect the services

In questo successivo passaggio, connettere i due servizi e configurare l'applicazione Web front-end per il recupero e l'impostazione delle informazioni di voto dal servizio 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.

L'infrastruttura di servizi offre la massima flessibilità nella comunicazione con Reliable Services.Service Fabric provides complete flexibility in how you communicate with reliable services. All'interno di una singola applicazione possono esserci servizi accessibili tramite TCP.Within a single application, you might have services that are accessible via TCP. Altri servizi potrebbero essere accessibili tramite un'API REST HTTP e altri ancora tramite Web Socket.Other services that might be accessible via an HTTP REST API and still other services could be accessible via web sockets. Per informazioni sulle opzioni disponibili e sui compromessi necessari, vedere Comunicazione con i servizi.For background on the options available and the tradeoffs involved, see Communicating with services.

In questa esercitazione usare l'API Web di ASP.NET Core e il proxy inverso di Service Fabric affinché il servizio Web front-end VotingWeb possa comunicare con il servizio back-end VotingData.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. Per impostazione predefinita, il proxy inverso viene configurato per usare la porta 19081. Dovrebbe funzionare per questa esercitazione.The reverse proxy is configured by default to use port 19081 and should work for this tutorial. La porta è impostata nel modello di ARM usato per configurare il cluster.The port is set in the ARM template used to set up the cluster. Per individuare quale porta viene usata, verificare il modello di cluster nella risorsa Microsoft.ServiceFabric/clusters o esaminare l'elemento HttpApplicationGatewayEndpoint nel manifesto del cluster.To find which port is used, look in the cluster template in the Microsoft.ServiceFabric/clusters resource or look at the HttpApplicationGatewayEndpoint element in the cluster Manifest.

Risorsa reverseProxyEndpointPort di Microsoft.ServiceFabric/clusters Microsoft.ServiceFabric/clusters reverseProxyEndpointPort resource

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

Per visualizzare l'elemento HttpApplicationGatewayEndpoint nel manifesto del cluster di Service Fabric locale:To view the HttpApplicationGatewayEndpoint element in the local Service Fabric cluster Manifest:

  1. Aprire una finestra del browser e passare a http://localhost:19080.Open a browser window and navigate to http://localhost:19080.
  2. Fare clic su Manifesto.Click Manifest.
  3. Annotare la porta dell'elemento HttpApplicationGatewayEndpoint.Make a note of the HttpApplicationGatewayEndpoint element port. Per impostazione predefinita, dovrebbe essere la 19081.By default this should be 19081. Se non è la 19081, è necessario modificare la porta nel metodo GetProxyAddress del codice VotesController.cs seguente.If it is not 19081, you will need to change the port in the GetProxyAddress method of the following VotesController.cs code.

Aggiornare il file VotesController.csUpdate the VotesController.cs file

Nel progetto VotingWeb aprire il file Controllers/VotesController.cs.In the VotingWeb project, open the Controllers/VotesController.cs file. Sostituire il contenuto della definizione di classe VotesController con il codice seguente e quindi salvare le modifiche.Replace the VotesController class definition contents with the following, then save your changes. Se la porta del proxy inverso che è stata individuata nel passaggio precedente non è la 19081, modificare la porta usata nel metodo GetProxyAddress da 19081 alla porta individuata.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';
    }
}

Descrizione dettagliata dell'applicazione di voto di esempioWalk through the voting sample application

L'applicazione di voto è costituita da due servizi:The voting application consists of two services:

  • Il servizio front-end Web (VotingWeb) - Un servizio front-end Web ASP.NET Core che gestisce la pagina Web e che espone le API Web per la comunicazione con il servizio 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.
  • Il servizio back-end (VotingData) - Un servizio Web ASP.NET Core che espone un'API per l'archiviazione dei risultati delle votazioni in un oggetto Reliable Dictionary reso persistente su 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.

Diagramma dell'applicazione

Quando l'utente vota nell'applicazione, si verificano gli eventi seguenti:When you vote in the application the following events occur:

  1. JavaScript invia la richiesta di voto all'API Web nel servizio front-end Web come una richiesta HTTP PUT.A JavaScript sends the vote request to the web API in the web front-end service as an HTTP PUT request.

  2. Il servizio front-end Web usa un proxy per individuare e inoltrare una richiesta PUT HTTP al servizio back-end.The web front-end service uses a proxy to locate and forward an HTTP PUT request to the back-end service.

  3. Il servizio back-end accetta la richiesta in ingresso e archivia il risultato aggiornato in un oggetto Reliable Dictionary, che viene replicato in più nodi all'interno del cluster e reso persistente su 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. Tutti i dati dell'applicazione sono archiviati nel cluster, quindi non è necessario alcun database.All the application's data is stored in the cluster, so no database is needed.

Eseguire il debug in Visual StudioDebug in Visual Studio

Durante il debug dell'applicazione in Visual Studio, viene usato un cluster di sviluppo locale di Service Fabric.When debugging application in Visual Studio, you are using a local Service Fabric development cluster. È possibile modificare l'esperienza di debug in base allo specifico scenario.You have the option to adjust your debugging experience to your scenario. In questa applicazione archiviare i dati nel servizio back-end usando un oggetto Reliable Dictionary.In this application, store data in the back-end service using a reliable dictionary. Visual Studio rimuove l'applicazione per impostazione predefinita quando si arresta il debugger.Visual Studio removes the application per default when you stop the debugger. La rimozione dell'applicazione determina la rimozione anche dei dati nel servizio back-end.Removing the application causes the data in the back-end service to also be removed. Per rendere persistenti i dati tra le sessioni di debug, è possibile modificare la proprietà Modalità di debug applicazione del progetto Voting in 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.

Per osservare che cosa avviene nel codice, completare la procedura seguente:To look at what happens in the code, complete the following steps:

  1. Aprire il file VotingWeb\VotesController.cs e impostare un punto di interruzione nel metodo Put dell'API Web (riga 63).Open the VotingWeb\VotesController.cs file and set a breakpoint in the web API's Put method (line 63).

  2. Aprire il file VotingData\VoteDataController.cs e impostare un punto di interruzione nel metodo Put dell'API Web (riga 53).Open the VotingData\VoteDataController.cs file and set a breakpoint in this web API's Put method (line 53).

  3. Premere F5 per avviare l'applicazione in modalità di debug.Press F5 to start the application in debug mode.

  4. Tornare al browser e fare clic su un'opzione di voto oppure aggiungere una nuova opzione di voto.Go back to the browser and click a voting option or add a new voting option. È stato raggiunto il primo punto di interruzione nel controller API del front-end Web.You hit the first breakpoint in the web front-end's api controller.

    1. In questa posizione, il codice JavaScript nel browser invia una richiesta al controller API Web nel servizio front-end.This is where the JavaScript in the browser sends a request to the web API controller in the front-end service.

      Aggiungere il servizio front-end di voto

    2. Per prima cosa, costruire l'URL del proxy inverso per il servizio back-end (1).First construct the URL to the ReverseProxy for the back-end service (1).

    3. Inviare quindi la richiesta HTTP PUT al proxy inverso (2).Then send the HTTP PUT Request to the ReverseProxy (2).
    4. Restituire infine la risposta dal servizio back-end al client (3).Finally the return the response from the back-end service to the client (3).
  5. Premere F5 per continuare.Press F5 to continue.

    1. Ora ci troviamo al punto di interruzione nel servizio back-end.You are now at the break point in the back-end service.

      Aggiungere il servizio back-end di voto

    2. Nella prima riga del metodo (1) usare StateManager per ottenere o aggiungere un oggetto Reliable Dictionary denominato counts.In the first line in the method (1) use the StateManager to get or add a reliable dictionary called counts.

    3. Tutte le interazioni con i valori in un oggetto Reliable Dictionary richiedono una transazione, che viene creata dall'istruzione using (2).All interactions with values in a reliable dictionary require a transaction, this using statement (2) creates that transaction.
    4. Nella transazione aggiornare il valore della chiave pertinente per l'opzione di voto ed eseguire il commit dell'operazione (3).In the transaction, update the value of the relevant key for the voting option and commits the operation (3). Dopo la restituzione del metodo Commit, i dati vengono aggiornati nel dizionario e replicati negli altri nodi del cluster.Once the commit method returns, the data is updated in the dictionary and replicated to other nodes in the cluster. A questo punto, i dati sono archiviati in modo sicuro nel cluster e il servizio back-end può eseguire il failover in altri nodi, rendendo comunque disponibili i dati.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. Premere F5 per continuare.Press F5 to continue.

Per interrompere la sessione di debug, premere MAIUSC+F5.To stop the debugging session, press Shift+F5.

Passaggi successiviNext steps

In questa parte dell'esercitazione si è appreso come:In this part of the tutorial, you learned how to:

  • Creare un servizio API Web ASP.NET Core come servizio Reliable con statoCreate an ASP.NET Core Web API service as a stateful reliable service
  • Creare un servizio applicazione Web ASP.NET Core come servizio Web senza statoCreate an ASP.NET Core Web Application service as a stateless web service
  • Usare il proxy inverso per comunicare con il servizio con statoUse the reverse proxy to communicate with the stateful service

Passare all'esercitazione successiva:Advance to the next tutorial: