Tutorial: Erstellen einer .NET Service Fabric-Anwendung
Dieses Tutorial ist der erste Teil einer Serie. In diesem Tutorial lernen Sie, wie Sie eine Azure Service Fabric-Anwendung mit einem ASP.NET Core-Web-API-Front-End und einem zustandsbehafteten Back-End-Dienst zum Speichern Ihrer Daten erstellen. Am Ende verfügen Sie über eine Abstimmungsanwendung mit einem ASP.NET Core-Web-Front-End, mit der Abstimmungsergebnisse im Cluster in einem zustandsbehafteten Back-End-Dienst gespeichert werden.
Für diese Tutorialreihe ist ein Windows-Entwicklungscomputer erforderlich. Wenn Sie die Abstimmungsanwendung nicht manuell erstellen möchten, können Sie den Quellcode für die fertige Anwendung herunterladen und mit Durchlaufen der Beispielanwendung für die Abstimmung fortfahren. Sie können auch ein Video mit einer exemplarischen Vorgehensweise in diesem Tutorial anzeigen.
In diesem Tutorial lernen Sie Folgendes:
- Erstellen eines ASP.NET Core-Web-API-Diensts als zustandsbehafteter zuverlässiger Dienst
- Erstellen eines ASP.NET Core-Webanwendungsdiensts als zustandsloser Webdienst
- Kommunizieren mit dem zustandsbehafteten Dienst unter Verwendung des Reverseproxys
Die Tutorialreihe veranschaulicht folgende Vorgehensweisen:
- Erstellen einer .NET Service Fabric-Anwendung (dieses Tutorial)
- Bereitstellen der Anwendung in einem Remotecluster
- Hinzufügen eines HTTPS-Endpunkts zu einem ASP.NET Core-Front-End-Dienst
- Konfigurieren von CI/CD mit Azure Pipelines
- Einrichten der Überwachung und Diagnose für die Anwendung
Voraussetzungen
Bevor Sie mit diesem Tutorial beginnen können, müssen Sie Folgendes tun:
- Wenn Sie kein Azure-Abonnement besitzen, können Sie ein kostenloses Konto erstellen.
- Installieren Sie Visual Studio 2019 (Version 15.5 oder höher) einschließlich der Workloads Azure-Entwicklung und ASP.NET und Webentwicklung.
- Installieren Sie das Service Fabric SDK.
Erstellen eines ASP.NET-Web-API-Diensts als zuverlässigen Dienst
Erstellen Sie mithilfe von ASP.NET Core zunächst das Web-Front-End der Abstimmungsanwendung. ASP.NET Core ist ein einfaches, plattformübergreifendes Webentwicklungsframework, das Sie zur Erstellung von modernen Benutzeroberflächen und Web-APIs verwenden können.
Damit Sie die Integration von ASP.NET Core mit Service Fabric vollständig verstehen, wird dringend empfohlen, sich ASP.NET Core in Service Fabric-Reliable Services anzusehen. Für einen schnellen Einstieg reicht es jedoch, wenn Sie vorerst nur diesem Tutorial folgen. Weitere Informationen zu ASP.NET Core finden Sie in der ASP.NET Core-Dokumentation.
So erstellen Sie den Dienst:
Öffnen Sie Visual Studio, indem Sie die Option Als Administrator ausführen verwenden.
Wählen Sie den Befehl Datei>Neu>Projekt aus, um ein neues Projekt zu erstellen.
Wählen Sie unter Neues Projekt erstellen die Option Cloud>Service Fabric-Anwendung aus. Wählen Sie Weiter aus.
Wählen Sie Stateless ASP.NET Core für den neuen Projekttyp aus, benennen Sie Ihren Dienst VotingWeb, und wählen Sie dann Erstellen aus.
Die nächste Seite zeigt eine Reihe von ASP.NET Core-Projektvorlagen. Wählen Sie in diesem Tutorial die Webanwendung (Model-View-Controller) und dann OK aus.
Visual Studio erstellt ein Anwendungs- und ein Dienstprojekt und zeigt sie im Visual Studio Projektmappen-Explorer an:
Aktualisieren der Datei „site.js“
Wechseln Sie zu wwwroot/js/site.js, und öffnen Sie die Datei. Ersetzen Sie den Inhalt der Datei durch den folgenden JavaScript-Code, der von den Home-Ansichten verwendet wird, und speichern Sie anschließend Ihre Änderungen.
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;
})
};
}]);
Aktualisieren der Datei „Index.cshtml“
Wechseln Sie zu Views/Home/Index.cshtml, und öffnen Sie die Datei. Diese Datei enthält die Ansicht, die für den Home Controller spezifisch ist. Ersetzen Sie den Inhalt durch den folgenden Code, und speichern Sie anschließend Ihre Änderungen.
@{
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>
Aktualisieren der Datei „_Layout.cshtml“
Wechseln Sie zu Views/Shared/_Layout.cshtml, und öffnen Sie die Datei. Diese Datei verfügt über das Standardlayout für die ASP.NET-App. Ersetzen Sie den Inhalt durch den folgenden Code, und speichern Sie anschließend Ihre Änderungen.
<!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>
Aktualisieren der Datei „VotingWeb.cs“
Öffnen der Datei VotingWeb.cs. Diese Datei erstellt den ASP.NET Core-Webhost innerhalb des zustandslosen Diensts unter Verwendung des WebListener-Webservers.
Fügen Sie am Anfang der Datei die using System.Net.Http;
Anweisung hinzu.
Ersetzen Sie die Funktion CreateServiceInstanceListeners()
durch den folgenden Code, und speichern Sie anschließend Ihre Änderungen.
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();
}))
};
}
Fügen Sie dann die folgende GetVotingDataServiceName
-Methode nach CreateServiceInstanceListeners()
hinzu, und speichern Sie anschließend Ihre Änderungen. Wenn GetVotingDataServiceName
abgerufen wird, wird der Name des Diensts zurückgegeben.
internal static Uri GetVotingDataServiceName(ServiceContext context)
{
return new Uri($"{context.CodePackageActivationContext.ApplicationName}/VotingData");
}
Hinzufügen der Datei „VotesController.cs“
Fügen Sie einen Controller hinzu, um Abstimmungsaktionen zu definieren. Klicken Sie mit der rechten Maustaste auf den Ordner Controller, und wählen Sie Hinzufügen>Neues Element>Visual C#>ASP.NET Core>Klasse hinzu. Nennen Sie die Datei VotesController.cs, und klicken Sie auf Hinzufügen.
Ersetzen Sie den Inhalt der Datei VotesController.cs durch den folgenden Code, und speichern Sie anschließend Ihre Änderungen. Unter Aktualisieren der Datei „VotesController.cs“ wird diese Datei dann für das Lesen und Schreiben von Abstimmungsdaten aus dem Back-End-Dienst angepasst. Vorläufig gibt der Controller statische Zeichenfolgendaten an die Ansicht zurück.
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);
}
}
}
Konfigurieren des Lauschports
Beim Erstellen des VotingWeb Front-End-Diensts wählt Visual Studio nach dem Zufallsprinzip einen Port aus, an dem der Dienst lauscht. Der VotingWeb-Dienst fungiert als Front-End für diese Anwendung und akzeptiert externen Datenverkehr. In diesem Abschnitt binden Sie diesen Dienst an einen festen und bekannten Port. Mit dem Dienstmanifest werden die Dienstendpunkte deklariert.
Öffnen Sie VotingWeb/PackageRoot/ServiceManifest.xml im Projektmappen-Explorer. Suchen Sie im Resources
Abschnitt das Endpoint
Element, und ändern Sie dann den Port
Wert zu 8080
.
Wenn Sie die Anwendung lokal bereitstellen und ausführen möchten, muss der Anwendungslauschport auf dem Computer geöffnet und verfügbar sein.
<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>
Aktualisieren Sie dann den Application URL
Eigenschaftswert im Projekt „Voting“, damit ein Webbrowser beim Debuggen der Anwendung mit dem korrekten Port geöffnet wird. Wählen Sie im Projektmappen-Explorer das Projekt Voting aus, und ändern Sie die Eigenschaft Application URL
zu 8080
.
Lokales Bereitstellen und Ausführen der Anwendung „Voting“
Sie können nun die Abstimmungsanwendung ausführen, um sie zu debuggen. Wählen Sie in Visual Studio F5, um die Anwendung für Ihren lokalen Service Fabric-Cluster im Debugmodus bereitzustellen. Die Anwendung schlägt fehl, wenn Sie Visual Studio zuvor nicht mithilfe der Option Als Administrator ausführen geöffnet haben.
Hinweis
Wenn Sie die Anwendung zum ersten Mal lokal ausführen und bereitstellen, erstellt Visual Studio einen lokalen Service Fabric-Cluster zur Nutzung für das Debuggen. Der Prozess zum Erstellen eines Clusters kann einige Zeit in Anspruch nehmen. Der Status der Clustererstellung wird im Ausgabefenster von Visual Studio angezeigt.
Nachdem die Abstimmungsanwendung in Ihrem lokalen Service Fabric-Cluster bereitgestellt wurde, wird Ihre Web-App automatisch auf einer Browserregisterkarte geöffnet. Sie ähnelt der im folgenden Beispiel:
Zum Beenden des Debuggens der Anwendung wechseln Sie zurück zu Visual Studio, und wählen Sie UMSCHALT+F5.
Hinzufügen eines zustandsbehafteten Back-End-Diensts zur Anwendung
Nachdem in der Anwendung nun ein ASP.NET-Web-API-Dienst ausgeführt wird, können Sie einen zustandsbehafteten zuverlässigen Dienst hinzufügen, um einige Daten in der Anwendung zu speichern.
Service Fabric ermöglicht eine konsistente und zuverlässige Speicherung von Daten direkt innerhalb des Diensts anhand von Reliable Collections. Bei Reliable Collections handelt es sich um eine Gruppe hochverfügbarer und zuverlässiger Sammlungsklassen, die jedem vertraut sind, der Erfahrung mit C#-Auflistungen hat.
So erstellen Sie einen Dienst, der einen Leistungsindikatorwert in einer zuverlässigen Sammlung speichert:
Klicken Sie im Projektmappen-Explorer im Anwendungsprojekt „Voting“ mit der rechten Maustaste auf Dienste, und wählen Sie Hinzufügen>Neuer Service Fabric-Dienst aus.
Wählen Sie im Dialogfeld Neuer Service Fabric-Dienst die Option Zustandsbehaftetes ASP.NET Core aus, nennen Sie den Dienst VotingData, und wählen Sie dann OK.
Nach Erstellung Ihres Dienstprojekts stehen Ihnen zwei Dienste in Ihrer Anwendung zur Verfügung. Bei der weiteren Erstellung Ihrer Anwendung können Sie weitere Dienste auf die gleiche Weise hinzufügen. Jeder Dienst kann unabhängig versioniert und aktualisiert werden.
Die nächste Seite zeigt eine Reihe von ASP.NET Core-Projektvorlagen. In diesem Tutorial wählen Sie API aus.
Visual Studio erstellt ein VotingData-Dienstprojekt und zeigt es im Projektmappen-Explorer an:
Hinzufügen der Datei „VoteDataController.cs“
Klicken Sie im Projekt VotingData mit der rechten Maustaste auf den Ordner Controllers, und wählen Sie Hinzufügen> Neues Element>Klasse aus. Nennen Sie die Datei VoteDataController.cs, und wählen Sie auf Hinzufügen. Ersetzen Sie den Inhalt der Datei durch den folgenden Code, und speichern Sie anschließend Ihre Änderungen.
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();
}
}
}
}
}
Verbinden der Dienste
In diesem Abschnitt verbinden Sie zwei Dienste. Sie erstellen die Front-End-Webanwendung, um Abstimmungsinformationen vom Back-End-Dienst abzurufen und dann die Informationen in der App festzulegen.
Service Fabric bietet Ihnen umfassende Flexibilität in der Art und Weise, wie Sie mit zuverlässigen Diensten kommunizieren. In einer einzigen Anwendung verfügen Sie möglicherweise über Dienste, die über TCP/IP, über eine HTTP-REST-API oder über das WebSocket-Protokoll zugänglich sind. Ausführliche Informationen zu den verfügbaren Optionen und deren Vor- und Nachteilen finden Sie unter Kommunizieren mit Diensten.
In diesem Tutorial verwenden Sie die ASP.NET Core-Web-API und den Service Fabric-Reverseproxy, damit der Front-End-Webdienst „VotingWeb“ mit dem Back-End-Datendienst „VotingData“ kommunizieren kann. Ein Reverseproxy ist standardmäßig für die Verwendung von Port 19081 konfiguriert. Der Port des Reverseproxys ist in der Azure Resource Manager-Vorlage zum Einrichten des Clusters festgelegt. Um zu ermitteln, welcher Port verwendet wird, suchen Sie in der Clustervorlage in der Microsoft.ServiceFabric/clusters
Ressource:
"nodeTypes": [
{
...
"httpGatewayEndpointPort": "[variables('nt0fabricHttpGatewayPort')]",
"isPrimary": true,
"vmInstanceCount": "[parameters('nt0InstanceCount')]",
"reverseProxyEndpointPort": "[parameters('SFReverseProxyPort')]"
}
],
Um den in Ihrem lokalen Entwicklungscluster verwendeten Port des Reverseproxys zu ermitteln, sehen Sie sich das HttpApplicationGatewayEndpoint
-Element im lokalen Service Fabric-Clustermanifest an:
- Um das Tool Service Fabric Explorer zu öffnen, öffnen Sie einen Browser, und wechseln Sie zu
http://localhost:19080
. - Wählen Sie Clustermanifest> aus.
- Notieren Sie sich den
HttpApplicationGatewayEndpoint
Elementport. Die Standardeinstellung ist der Port 19081. Wenn es nicht 19081 ist, ändern Sie den Port in derGetProxyAddress
Methode des VotesController.cs Codes, wie im nächsten Abschnitt beschrieben.
Aktualisieren der Datei „VotesController.cs“
Öffnen Sie im Projekt VotingWeb die Datei Controllers/VotesController.cs. Ersetzen Sie den Inhalt der Definition der Klasse VotesController
durch den folgenden Code, und speichern Sie anschließend Ihre Änderungen. Wenn der Reverseproxyport, den Sie im vorherigen Schritt ermittelt haben, nicht 19081 ist, ändern Sie den Port in der Methode GetProxyAddress
verwendeten Port von 19081
in den ermittelten Port.
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';
}
}
Durchlaufen der Beispielanwendung für die Abstimmung
Die Abstimmungsanwendung besteht aus zwei Diensten:
- Ein Web-Front-End-Dienst (VotingWeb): Ein ASP.NET Core-Web-Front-End-Dienst, der die Webseite bereitstellt und Web-APIs für die Kommunikation mit dem Back-End-Dienst verfügbar macht.
- Ein Back-End-Dienst (VotingData): Ein ASP.NET Core-Web-Dienst, der eine API verfügbar macht, um die Abstimmungsergebnisse in einem zuverlässigen Wörterbuch zu speichern, das dauerhaft auf dem Datenträger vorhanden ist.
Beim Abstimmen in der Anwendung treten die folgenden Ereignisse ein:
Eine JavaScript-Datei sendet die Abstimmungsanforderung als HTTP PUT-Anforderung an die Web-API im Web-Front-End-Dienst.
Der Web-Front-End-Dienst nutzt einen Proxy, um eine HTTP PUT-Anforderung zu lokalisieren und an den Back-End-Dienst weiterzuleiten.
Der Back-End-Dienst übernimmt die eingehende Anforderung und speichert das aktualisierte Ergebnis in einem zuverlässigen Wörterbuch. Das Wörterbuch wird auf mehrere Knoten im Cluster repliziert und auf dem Datenträger gespeichert. Alle Daten der Anwendung werden im Cluster gespeichert, sodass keine Datenbank erforderlich ist.
Debuggen in Visual Studio
Wenn Sie die Anwendung in Visual Studio debuggen, verwenden Sie einen lokalen Service Fabric-Entwicklungscluster. Sie können Ihre Oberfläche für das Debuggen an Ihr Szenario anpassen.
In dieser Anwendung speichern Sie Daten im Back-End-Dienst, indem Sie ein zuverlässiges Wörterbuch verwenden. Standardmäßig wird die Anwendung von Visual Studio entfernt, wenn Sie den Debugger beenden. Die Entfernung der Anwendung führt dazu, dass auch die Daten im Back-End-Dienst entfernt werden. Um die Daten zwischen den Debugsitzungen beizubehalten, können Sie den Debugmodus für die Anwendung als Eigenschaft im Projekt Voting in Visual Studio ändern.
Führen Sie die folgenden Schritte aus, um zu sehen, was im Code passiert:
Öffnen Sie die Datei VotingWeb\VotesController.cs, und legen Sie in der
Put
-Methode der Web-API (Zeile 72) einen Haltepunkt fest.Öffnen Sie die Datei VotingData\VoteDataController.cs, und legen Sie in der
Put
-Methode der Web-API (Zeile 54) einen Haltepunkt fest.Wählen Sie F5, um die Anwendung im Debugmodus auszuführen.
Wechseln Sie zurück in den Browser, und wählen Sie eine Abstimmungsoption, oder fügen Sie eine neue Abstimmungsoption hinzu. Der erste Breakpoint befindet sich im API-Controller des Web-Front-Ends.
Das JavaScript im Browser sendet eine Anforderung an den Web-API-Controller im Front-End-Dienst:
- Erstellen Sie zunächst die URL zum Reverseproxy für den Back-End-Dienst. (1)
- Senden Sie anschließend die HTTP PUT-Anforderung an den Reverseproxy. (2)
- Geben Sie zum Schluss die Antwort vom Back-End-Dienst an den Client zurück. (3)
Wählen Sie F5, um fortzufahren.
Sie befinden sich jetzt am Breakpoint im Back-End-Dienst:
- Verwenden Sie in der ersten Zeile der Methode
stateManager
, um ein zuverlässiges Wörterbuch mit dem Namencounts
abzurufen bzw. hinzuzufügen. (1) - Alle Interaktionen mit Werten in einem zuverlässigen Wörterbuch erfordern eine Transaktion. Diese
using
Anweisung erstellt diese Transaktion. (2) - Aktualisieren Sie in der Transaktion den Wert des relevanten Schlüssels für die Abstimmungsoption, und committen Sie den Vorgang. Wenn die
commit
Methode zurückgegeben wird, werden die Daten im Wörterbuch aktualisiert. Anschließend wird sie auf andere Knoten im Cluster repliziert. Die Daten sind jetzt sicher im Cluster gespeichert, und der Back-End-Dienst kann das Failover auf andere Knoten durchführen, während die Daten weiterhin verfügbar sind. (3)
- Verwenden Sie in der ersten Zeile der Methode
Wählen Sie F5, um fortzufahren.
Wählen Sie UMSCHALT+F5, um die Debugsitzung zu beenden.
Nächster Schritt
Fahren Sie mit dem nächsten Tutorial fort: