Compartir vía


Tutorial: Crear una aplicación .NET de Service Fabric

Este tutorial es la primera parte de una serie. En este tutorial aprenderá a crear una aplicación de Azure Service Fabric que tiene un front-end de ASP.NET Core Web API y un servicio back-end con estado para almacenar los datos. Cuando termine, tendrá una aplicación de votación que tiene un front-end web de ASP.NET Core que guarda los resultados de la votación en un servicio back-end con estado en el clúster.

Esta serie de tutoriales necesita un ordenador de desarrollador de Windows. Si no desea crear manualmente la aplicación de votación, puede descargar el código fuente de la aplicación terminada y pasar directamente al Tutorial de la aplicación de ejemplo de votación. También puede ver una guía en vídeo de este tutorial.

Un diagrama que muestra un front-end de la API AngularJS+ASP.NET, conexión a un servicio de back-end con estado en Service Fabric.

En este tutorial, aprenderá a:

  • Crear un servicio de ASP.NET Core Web API como un servicio de confianza con estado
  • Crear un servicio de ASP.NET Core Web Application como un servicio de confianza sin estado
  • Usar un proxy inverso para comunicarse con el servicio con estado

En esta serie de tutoriales se muestra cómo realizar las siguientes acciones:

Requisitos previos

Antes de empezar este tutorial:

Creación de un servicio de ASP.NET Web API como un servicio de confianza

En primer lugar, cree el front-end web de la aplicación de votación mediante ASP.NET Core. ASP.NET Core es un marco de desarrollo web ligero multiplataforma, que puede usar para crear modernas interfaces de usuario web y API web.

Para obtener una descripción completa de cómo se integra ASP.NET Core con Service Fabric, se recomienda fehacientemente que revise ASP.NET Core en Reliable Services de Service Fabric. De momento, puede seguir este tutorial para empezar a trabajar rápidamente. Para más información sobre ASP.NET Core, vea Documentación de ASP.NET Core.

Para crear el servicio:

  1. Abra Visual Studio con la opción Ejecutar como administrador.

  2. Seleccione Archivo>Nuevo>Proyecto para crear un nuevo proyecto.

  3. En Crear un nuevo proyecto, seleccione Nube>Aplicación de Service Fabric. Seleccione Siguiente.

    Captura de pantalla que muestra el cuadro de diálogo Crear un nuevo proyecto en Visual Studio.

  4. Seleccione ASP.NET Core sin estado para el nuevo tipo de proyecto, asigne un nombre al servicio VotingWeby, a continuación, seleccione Crear.

    Captura de pantalla que muestra cómo elegir un servicio web ASP.NET en el nuevo panel de servicio.

  5. En el panel siguiente se muestra un conjunto de plantillas de proyecto ASP.NET Core. Para este tutorial, seleccione Aplicación web (controlador de vista de modelos) y luego seleccione Aceptar.

    Captura de pantalla que muestra la selección del tipo de proyecto ASP.NET.

    Visual Studio crea una aplicación y un proyecto de servicio, y luego los muestra en el Explorador de soluciones de Visual Studio.

    Captura de pantalla que muestra el Explorador de soluciones después de crear la aplicación mediante el servicio de API web ASP.NET Core.

Actualización del archivo site.js

Vaya a wwwroot/js/site.js y abra el archivo. Reemplace los contenidos del archivo por el código de JavaScript siguiente que usan las vistas de inicio y guarde los cambios.

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

Actualización del archivo Index.cshtml

Vaya a Views/Home/Index.cshtml y abra el archivo. Este archivo tiene la vista específica del controlador Inicio. Reemplace su contenido por el siguiente código y guarde los cambios.

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

Actualización del archivo _Layout.cshtml

Vaya a Views/Shared/_Layout.cshtml y abra el archivo. Este archivo tiene el diseño predeterminado de la aplicación ASP.NET. Reemplace su contenido por el siguiente código y guarde los cambios.

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

Actualización del archivo VotingWeb.cs

Abra el archivo VotingWeb.cs. El archivo crea el elemento WebHost de ASP.NET Core dentro del servicio sin estado con el servidor web de WebListener.

Al principio del archivo, agregue la directiva using System.Net.Http;.

Reemplace la función CreateServiceInstanceListeners() por el código siguiente y guarde los cambios.

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

Luego agregue el método GetVotingDataServiceName siguiente después de CreateServiceInstanceListeners() y guarde los cambios. GetVotingDataServiceName devuelve el nombre del servicio cuando se sondea.

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

Incorporación del archivo VotesController.cs

Agregue un controlador para definir las acciones de votación. Haga clic con el botón derecho en la carpeta Controladores y seleccione Agregar>Nuevo elemento>Visual C#>ASP.NET Core>Clase. Asigne al archivo el nombre VotesController.csy y seleccione Agregar.

Reemplace el contenido del archivo VotesController.cs por el siguiente código y guarde los cambios. Más adelante, en Actualización del archivo VotesController.cs, este archivo se modifica para leer y escribir los datos de votación desde el servicio back-end. Por ahora, el controlador devuelve datos de cadena estática a la vista.

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

Configuración del puerto de escucha

Cuando se crea el servicio front-end VotingWeb, Visual Studio selecciona aleatoriamente un puerto en el que el servicio realiza la escucha. El servicio VotingWeb actúa como front-end para esta aplicación y acepta tráfico externo. En esta sección, enlazará ese servicio a un puerto fijo y conocido. El manifiesto del servicio declara los puntos de conexión de servicio.

En el Explorador de soluciones, abra VotingWeb/PackageRoot/ServiceManifest.xml. En la sección Resources, busque el elemento Endpoint y, a continuación, cambie el valor de Port a 8080.

Para implementar y ejecutar la aplicación localmente, el puerto de escucha de la aplicación debe estar abierto y disponible en el equipo.

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

Actualice también el valor de la propiedad Application URL en el proyecto Voting para que un explorador web se abra en el puerto correcto al depurar la aplicación. En el Explorador de soluciones, seleccione el proyecto Voting y actualice la propiedad Application URL a 8080.

Implementación y ejecución local de la aplicación Voting

Ahora puede ejecutar la aplicación Voting para depurarla. En Visual Studio, seleccione F5 para implementar la aplicación en el clúster local de Service Fabric en modo de depuración. La aplicación presenta un error si no abrió Visual Studio anteriormente con la opción de Ejecutar como administrador.

Nota:

La primera vez que ejecute e implemente la aplicación localmente, Visual Studio creará un clúster local de Service Fabric para usar en la depuración. El proceso para crear un clúster puede tardar algún tiempo. El estado de creación del clúster se muestra en la ventana de salida de Visual Studio.

Una vez que la aplicación Voting se implemente en el clúster local de Service Fabric, la aplicación web se abre automáticamente en una pestaña del explorador. Tiene un aspecto similar a este ejemplo:

Captura de pantalla que muestra el front-end de la aplicación en un explorador.

Para detener la depuración de la aplicación, vuelva a Visual Studio y seleccione Mayús+F5.

Adición de un servicio back-end con estado a la aplicación

Ahora que se ejecuta un servicio de ASP.NET Web API en la aplicación, agregue un servicio de confianza con estado para almacenar datos en la aplicación.

Puede usar Service Fabric para almacenar de forma coherente y confiable su estado justo dentro de su servicio mediante colecciones de confianza. Las colecciones de confianza son un conjunto de clases de colecciones de alta disponibilidad y confiabilidad que le resultará familiar a cualquiera que tenga experiencia usado colecciones de C#.

Para crear un servicio que almacena un valor de contador en una colección de confianza:

  1. En el Explorador de soluciones, haga clic con el botón derecho en Servicios, en el proyecto de aplicación Voting y seleccione Agregar>Nuevo servicio de Service Fabric.

  2. En el cuadro de diálogo Nuevo servicio de Service Fabric, seleccione ASP.NET Core con estado, asigne el nombre de VotingData al servicio y seleccione Aceptar.

    Después de crear el proyecto de servicio, tendrá dos servicios en la aplicación. Mientras continúa la creación de la aplicación, puede agregar más servicios de la misma forma. El control de versiones y la actualización de cada servicio pueden realizarse de manera independiente.

  3. En el panel siguiente se muestra un conjunto de plantillas de proyecto ASP.NET Core. Para este tutorial, seleccione API.

    Visual Studio crea el proyecto de servicio VotingData y lo muestra en el Explorador de soluciones:

    Captura de pantalla que muestra el proyecto de servicio VotingData en el Explorador de soluciones.

Incorporación del archivo VoteDataController.cs

En el proyecto VotingData haga clic con el botón derecho en la carpeta Controladores y seleccione Agregar>Nuevo elemento>Clase. Asigne al archivo el nombre VoteDataController.cs y seleccione Agregar. Reemplace el contenido del archivo por el siguiente código y guarde los cambios.

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

Conexión de los servicios

En esta sección, conectará dos servicios. Haga que la aplicación web de front-end obtenga la información de votación del servicio back-end y luego establezca la información en la app.

Service Fabric le proporciona una flexibilidad completa en el modo de comunicación con los servicios confiables. Dentro de una única aplicación, es posible que tenga servicios que sean accesibles a través de TCP/IP, a través de una API de REST HTTP, o de un protocolo WebSocket. Para más información sobre las opciones que están disponibles y sus inconvenientes, consulte Conexión y comunicación con servicios.

En este tutorial se usa la Web API de ASP.NET Core y el proxy inverso de Service Fabric para que el servicio web VotingWeb de front-end pueda comunicarse con el servicio VotingData de back-end. De forma predeterminada, se configura un proxy inverso para usar el puerto 19081. El puerto del proxy inverso se establece en la plantilla de Azure Resource Manager que configura el clúster. Para ver qué puerto se utiliza, busque en la plantilla de clúster en el recurso Microsoft.ServiceFabric/clusters:

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

Para encontrar el puerto del proxy inverso que se usa en el clúster de desarrollo local, consulte el elemento HttpApplicationGatewayEndpoint en el manifiesto del clúster de Service Fabric local:

  1. Para abrir la herramienta Service Fabric Explorer, abra el explorador y vaya a http://localhost:19080.
  2. Seleccione Clúster>Manifiesto.
  3. Anote el puerto del elemento HttpApplicationGatewayEndpoint. De forma predeterminada, el puerto es el 19081. Si no es 19081, cambie el puerto en el método GetProxyAddress del código VotesController.cs tal y como se describe en la sección siguiente.

Actualización del archivo VotesController.cs

En el proyecto VotingWeb, abra el archivo Controllers/VotesController.cs. Reemplace el contenido de la definición de clase VotesController por el siguiente código y guarde los cambios. Si el puerto de proxy inverso que detectó en el paso anterior no es 19081, cambie el puerto del método GetProxyAddress de 19081 al puerto que detectó.

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';
    }
}

Tutorial de la aplicación de ejemplo de votación

La aplicación de votación consta de dos servicios:

  • Un servicio front-end web (VotingWeb): servicio front-end web de ASP.NET Core, que sirve la página web y expone API web para comunicarse con el servicio back-end.
  • Un servicio back-end (VotingData): un servicio web de ASP.NET Core, que expone una API para almacenar los resultados de una votación en un diccionario de confianza que se conserva en el disco.

Diagrama que muestra los servicios de aplicación.

Al votar en la aplicación, se producen los eventos siguientes:

  1. Un archivo JavaScript envía la solicitud de votación a la API web del servicio front-end web como una solicitud HTTP PUT.

  2. El servicio front-end web usa un proxy para localizar y reenviar una solicitud HTTP PUT al servicio back-end.

  3. El servicio back-end toma la solicitud entrante y almacena el resultado actualizado en un diccionario de confianza. El diccionario se replica en varios nodos del clúster y se conserva en el disco. Todos los datos de la aplicación se almacenan en el clúster, por lo que no se necesita una base de datos.

Depurar en Visual Studio

Cuando se depura una aplicación en Visual Studio, se usa un clúster de desarrollo de Service Fabric local. Puede ajustar la experiencia de depuración a su escenario.

En esta aplicación, los datos se almacenan en el servicio back-end mediante un diccionario de confianza. Visual Studio quita la aplicación de forma predeterminada cuando se detiene el depurador. Cuando se quita la aplicación, los datos del servicio back-end también se quitan. Para conservar los datos entre sesiones de depuración, puede cambiar el modo de depuración de la aplicación como una propiedad del proyecto Voting en Visual Studio.

Para ver lo que ocurre en el código, siga estos pasos:

  1. Abra el archivo VotingWeb\VotesController.cs y establezca un punto de interrupción en el método Put (línea 72) de la API web.

  2. Abra el archivo VotingData\VoteDataController.cs y establezca un punto de interrupción en el método Put (línea 54) de la API web.

  3. Seleccione F5 para iniciar la aplicación en modo de depuración.

  4. Vuelva al explorador y seleccione una opción de votación o agregue una nueva opción de votación. Alcanzará el primer punto de interrupción del controlador de API del front-end web.

    El JavaScript del explorador envía una solicitud al controlador de API web del servicio front-end:

    Captura de pantalla que muestra cómo agregar un servicio front-end para votar.

    1. Primero, construya la dirección URL para el valor de proxy inverso del servicio back-end. (1)
    2. A continuación, envíe la solicitud PUT de HTTP al proxy inverso. (2)
    3. Por último, devuelva la respuesta desde el servicio back-end al cliente. (3)
  5. Seleccione F5 para continuar.

    Ya está en el punto de interrupción del servicio back-end:

    Captura de pantalla que muestra cómo agregar un voto al servicio back-end.

    1. En la primera línea del método, use stateManager para obtener o agregar un diccionario de confianza denominado counts. (1)
    2. Todas las interacciones que tienen valores en un diccionario de confianza requieren una transacción. Esta instrucción using crea esa transacción. (2)
    3. Después, en la transacción, actualice el valor de la tecla correspondiente para la opción de votación y confirme la operación. Cuando el método commit devuelve, los datos se actualizan en el diccionario. A continuación, se replica en otros nodos del clúster. Los datos ahora están almacenados de forma segura en el clúster y el servicio back-end puede conmutar por error a otros nodos y seguir teniendo los datos disponibles. (3)
  6. Seleccione F5 para continuar.

Para detener la sesión de depuración, seleccione Mayús+F5.

Paso siguiente

Avance hasta el siguiente tutorial: