Rychlý start: Použití Azure Cache for Redis v .NET Core
V tomto rychlém startu začleníte Azure Cache for Redis do aplikace .NET Core, abyste měli přístup k zabezpečené vyhrazené mezipaměti, která je přístupná z libovolné aplikace v Azure. Konkrétně používáte klienta StackExchange.Redis s kódem jazyka C# v aplikaci konzoly .NET Core.
Přeskočte na kód na GitHub
Pokud chcete přeskočit přímo na kód, podívejte se na rychlý start pro .NET Core na GitHub.
Požadavky
- Předplatné Azure – vytvořte si ho zdarma.
- Sada .NET Core SDK
Vytvoření mezipaměti
Pokud chcete vytvořit mezipaměť, přihlaste se k Azure Portal a vyberte Vytvořit prostředek.
Na stránce Nový vyberte Databáze a pak vyberte Azure Cache for Redis.
Na stránce Nový Redis Cache nakonfigurujte nastavení nové mezipaměti.
Nastavení Volba hodnoty Popis Předplatné Rozevírací seznam a vyberte své předplatné. Předplatné, ve kterém chcete vytvořit tuto novou Azure Cache for Redis instance. Skupina prostředků Rozevírací seznam a vyberte skupinu prostředků nebo vyberte Vytvořit novou a zadejte název nové skupiny prostředků. Název skupiny prostředků, ve které chcete vytvořit mezipaměť a další prostředky. Když všechny prostředky aplikace dáte do jedné skupiny prostředků, můžete je snadno spravovat nebo odstraňovat společně. Název DNS Zadejte jedinečný název. Název mezipaměti musí být řetězec o 1 až 63 znacích, který obsahuje pouze číslice, písmena nebo pomlčky. Název musí začínět a končovat číslem nebo písmenem a nesmí obsahovat po sobě jdoucí pomlčky. Název hostitele instance mezipaměti bude <DNS name> .redis.cache.windows.net. Umístění Rozevírací seznam a vyberte umístění. Vyberte oblast blízko jiných služeb, které budou používat vaši mezipaměť. Typ mezipaměti Rozevírací seznam a vyberte vrstvu. Úroveň určuje velikost, výkon a funkce, které jsou pro mezipaměť k dispozici. Další informace najdete v tématu Azure Cache for Redis . Vyberte kartu Sítě nebo vyberte tlačítko Sítě v dolní části stránky.
Na kartě Sítě vyberte metodu připojení.
Vyberte kartu Další: Upřesnit nebo vyberte tlačítko Další: Upřesnit v dolní části stránky.
Na kartě Upřesnit instance základní nebo standardní mezipaměti vyberte přepínač Povolit, pokud chcete povolit port, který není TLS. Můžete také vybrat, kterou verzi Redis chcete použít, a to buď 4, nebo 6.
Na kartě Upřesnit pro instanci služby Premium Cache nakonfigurujte nastavení pro porty bez TLS, clustering a trvalost dat. Můžete také vybrat, kterou verzi Redis chcete použít, a to buď 4, nebo 6.
Vyberte kartu Další: Značky nebo vyberte tlačítko Další: Značky v dolní části stránky.
Volitelně můžete na kartě Značky zadat název a hodnotu, pokud chcete prostředek kategorizovat.
Vyberte Zkontrolovat a vytvořit. Budete na kartě Zkontrolovat a vytvořit, kde Azure ověří vaši konfiguraci.
Jakmile se zobrazí zelená zpráva Ověření bylo předáno, vyberte Vytvořit.
Vytvoření mezipaměti chvíli trvá. Průběh můžete sledovat na Azure Cache for Redis přehledu. Když se stav zobrazí jako Spuštěno, je mezipaměť připravená k použití.
Načtení názvu hostitele, portů a přístupových klíčů z Azure Portal
Pro připojení k instanci Azure Cache for Redis potřebují klienti mezipaměti název hostitele, porty a klíč pro mezipaměť. Někteří klienti mohou tyto položky označovat trochu odlišnými názvy. Název hostitele, porty a klíče můžete získat z Azure Portal .
Přístupové klíče získáte tak, že v levé navigaci v mezipaměti vyberete Přístupové klíče.

Pokud chcete získat název hostitele a porty, v levém navigačním panelu mezipaměti vyberte Vlastnosti. Název hostitele má tvar <DNS name> .redis.cache.windows.net.

Poznamenejte si NÁZEV HOSTITELE a Primární přístupový klíč. Tyto hodnoty později použijete k vytvoření tajného kódu CacheConnection.
Vytvoření konzolové aplikace
Otevřete nové okno příkazového řádku a spuštěním následujícího příkazu vytvořte novou konzolovou aplikaci .NET Core:
dotnet new console -o Redistest
V okně příkazového řádku přejděte do nového adresáře projektu Redistest.
Přidání nástroje Secret Manager do projektu
V této části do svého projektu přidáte nástroj Secret Manager. Nástroj Secret Manager ukládá citlivá data související s vývojem mimo strom vašeho projektu. Tento přístup pomáhá zabránit náhodnému sdílení tajných kódů aplikace ve zdrojovém kódu.
Otevřete soubor Redistest.csproj. Přidejte element DotNetCliToolReference zahrnující Microsoft.Extensions.SecretManager.Tools. Přidejte také element UserSecretsId, jak je znázorněno níže, a uložte soubor.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<UserSecretsId>Redistest</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" />
</ItemGroup>
</Project>
Spuštěním následujícího příkazu přidejte k projektu balíček Microsoft.Extensions.Configuration.UserSecrets:
dotnet add package Microsoft.Extensions.Configuration.UserSecrets
Spuštěním následujícího příkazu balíčky obnovte:
dotnet restore
Po nahrazení zástupných znaků (včetně ostrých závorek) názvu mezipaměti a primárního přístupového klíče spusťte v okně příkazové řádku následující příkaz, který uloží nový tajný kód s názvem CacheConnection:
dotnet user-secrets set CacheConnection "<cache name>.redis.cache.windows.net,abortConnect=false,ssl=true,allowAdmin=true,password=<primary-access-key>"
K souboru Program.cs přidejte následující příkaz using:
using Microsoft.Extensions.Configuration;
K třídě Program v souboru Program.cs přidejte následující členy. Tento kód inicializuje konfiguraci pro přístup k tajnému kódu uživatele Azure Cache for Redis připojovací řetězec.
private static IConfigurationRoot Configuration { get; set; }
const string SecretName = "CacheConnection";
private static void InitializeConfiguration()
{
var builder = new ConfigurationBuilder()
.AddUserSecrets<Program>();
Configuration = builder.Build();
}
Konfigurace klienta mezipaměti
V této části nakonfigurujete konzolovou aplikaci, aby pro .NET používala klienta StackExchange.Redis.
V okně příkazového řádku spusťte v adresáři projektu Redistest následující příkaz:
dotnet add package StackExchange.Redis
Po dokončení instalace budete moct se svým projektem používat klienta mezipaměti StackExchange.Redis.
Připojení k mezipaměti
K souboru Program.cs přidejte následující příkaz using:
using StackExchange.Redis;
Připojení k Azure Cache for Redis spravuje ConnectionMultiplexer třída . V klientské aplikaci byste měli tuto třídu sdílet a opakovaně používat. Nevytvářejte pro každou operaci nové připojení.
V souboru Program.cs přidejte k třídě Program konzolové aplikace následující členy:
private static Lazy<ConnectionMultiplexer> lazyConnection = CreateConnection();
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
private static Lazy<ConnectionMultiplexer> CreateConnection()
{
return new Lazy<ConnectionMultiplexer>(() =>
{
string cacheConnection = Configuration[SecretName];
return ConnectionMultiplexer.Connect(cacheConnection);
});
}
Tento přístup ke sdílení instance ConnectionMultiplexer v aplikaci používá statickou vlastnost, která vrací připojenou instanci. Tento kód poskytuje způsob inicializace pouze jedné připojené instance ConnectionMultiplexer, který je bezpečný pro přístup z více vláken. abortConnect hodnota je nastavená na false, což znamená, že volání bude úspěšné i v případě, že Azure Cache for Redis není vytvořeno. Klíčovou vlastností ConnectionMultiplexer je automatické obnovení připojení k mezipaměti po vyřešení problémů se sítí nebo jiných příčin.
Hodnota tajného kódu CacheConnection se používá jako parametr hesla a je možné k ní získat přístup použitím zprostředkovatele konfigurace Secret Manager.
Zpracování redisConnectionException a SocketException opětovným připojením
Doporučeným postupem při volání metod na je pokus o vyřešení a automatické výjimky uzavřením a ConnectionMultiplexer RedisConnectionException SocketException obnovením připojení.
Do souboru Program.cs přidejte následující příkazy using:
using System.Net.Sockets;
using System.Threading;
V souboru Program.cs přidejte do třídy následující Program členy:
private static IConfigurationRoot Configuration { get; set; }
private static long _lastReconnectTicks = DateTimeOffset.MinValue.UtcTicks;
private static DateTimeOffset _firstErrorTime = DateTimeOffset.MinValue;
private static DateTimeOffset _previousErrorTime = DateTimeOffset.MinValue;
private static SemaphoreSlim _reconnectSemaphore = new SemaphoreSlim(initialCount: 1, maxCount: 1);
private static SemaphoreSlim _initSemaphore = new SemaphoreSlim(initialCount: 1, maxCount: 1);
private static ConnectionMultiplexer _connection;
private static bool _didInitialize = false;
// In general, let StackExchange.Redis handle most reconnects,
// so limit the frequency of how often ForceReconnect() will
// actually reconnect.
public static TimeSpan ReconnectMinInterval => TimeSpan.FromSeconds(60);
// If errors continue for longer than the below threshold, then the
// multiplexer seems to not be reconnecting, so ForceReconnect() will
// re-create the multiplexer.
public static TimeSpan ReconnectErrorThreshold => TimeSpan.FromSeconds(30);
public static TimeSpan RestartConnectionTimeout => TimeSpan.FromSeconds(15);
public static int RetryMaxAttempts => 5;
public static ConnectionMultiplexer Connection { get { return _connection; } }
private static async Task InitializeAsync()
{
if (_didInitialize)
{
throw new InvalidOperationException("Cannot initialize more than once.");
}
var builder = new ConfigurationBuilder()
.AddUserSecrets<Program>();
Configuration = builder.Build();
_connection = await CreateConnectionAsync();
_didInitialize = true;
}
// This method may return null if it fails to acquire the semaphore in time.
// Use the return value to update the "connection" field
private static async Task<ConnectionMultiplexer> CreateConnectionAsync()
{
if (_connection != null)
{
// If we already have a good connection, let's re-use it
return _connection;
}
try
{
await _initSemaphore.WaitAsync(RestartConnectionTimeout);
}
catch
{
// We failed to enter the semaphore in the given amount of time. Connection will either be null, or have a value that was created by another thread.
return _connection;
}
// We entered the semaphore successfully.
try
{
if (_connection != null)
{
// Another thread must have finished creating a new connection while we were waiting to enter the semaphore. Let's use it
return _connection;
}
// Otherwise, we really need to create a new connection.
string cacheConnection = Configuration["CacheConnection"].ToString();
return await ConnectionMultiplexer.ConnectAsync(cacheConnection);
}
finally
{
_initSemaphore.Release();
}
}
private static async Task CloseConnectionAsync(ConnectionMultiplexer oldConnection)
{
if (oldConnection == null)
{
return;
}
try
{
await oldConnection.CloseAsync();
}
catch (Exception)
{
// Ignore any errors from the oldConnection
}
}
/// <summary>
/// Force a new ConnectionMultiplexer to be created.
/// NOTES:
/// 1. Users of the ConnectionMultiplexer MUST handle ObjectDisposedExceptions, which can now happen as a result of calling ForceReconnectAsync().
/// 2. Call ForceReconnectAsync() for RedisConnectionExceptions and RedisSocketExceptions. You can also call it for RedisTimeoutExceptions,
/// but only if you're using generous ReconnectMinInterval and ReconnectErrorThreshold. Otherwise, establishing new connections can cause
/// a cascade failure on a server that's timing out because it's already overloaded.
/// 3. The code will:
/// a. wait to reconnect for at least the "ReconnectErrorThreshold" time of repeated errors before actually reconnecting
/// b. not reconnect more frequently than configured in "ReconnectMinInterval"
/// </summary>
public static async Task ForceReconnectAsync()
{
var utcNow = DateTimeOffset.UtcNow;
long previousTicks = Interlocked.Read(ref _lastReconnectTicks);
var previousReconnectTime = new DateTimeOffset(previousTicks, TimeSpan.Zero);
TimeSpan elapsedSinceLastReconnect = utcNow - previousReconnectTime;
// If multiple threads call ForceReconnectAsync at the same time, we only want to honor one of them.
if (elapsedSinceLastReconnect < ReconnectMinInterval)
{
return;
}
try
{
await _reconnectSemaphore.WaitAsync(RestartConnectionTimeout);
}
catch
{
// If we fail to enter the semaphore, then it is possible that another thread has already done so.
// ForceReconnectAsync() can be retried while connectivity problems persist.
return;
}
try
{
utcNow = DateTimeOffset.UtcNow;
elapsedSinceLastReconnect = utcNow - previousReconnectTime;
if (_firstErrorTime == DateTimeOffset.MinValue)
{
// We haven't seen an error since last reconnect, so set initial values.
_firstErrorTime = utcNow;
_previousErrorTime = utcNow;
return;
}
if (elapsedSinceLastReconnect < ReconnectMinInterval)
{
return; // Some other thread made it through the check and the lock, so nothing to do.
}
TimeSpan elapsedSinceFirstError = utcNow - _firstErrorTime;
TimeSpan elapsedSinceMostRecentError = utcNow - _previousErrorTime;
bool shouldReconnect =
elapsedSinceFirstError >= ReconnectErrorThreshold // Make sure we gave the multiplexer enough time to reconnect on its own if it could.
&& elapsedSinceMostRecentError <= ReconnectErrorThreshold; // Make sure we aren't working on stale data (e.g. if there was a gap in errors, don't reconnect yet).
// Update the previousErrorTime timestamp to be now (e.g. this reconnect request).
_previousErrorTime = utcNow;
if (!shouldReconnect)
{
return;
}
_firstErrorTime = DateTimeOffset.MinValue;
_previousErrorTime = DateTimeOffset.MinValue;
ConnectionMultiplexer oldConnection = _connection;
await CloseConnectionAsync(oldConnection);
_connection = null;
_connection = await CreateConnectionAsync();
Interlocked.Exchange(ref _lastReconnectTicks, utcNow.UtcTicks);
}
finally
{
_reconnectSemaphore.Release();
}
}
// In real applications, consider using a framework such as
// Polly to make it easier to customize the retry approach.
private static async Task<T> BasicRetryAsync<T>(Func<T> func)
{
int reconnectRetry = 0;
int disposedRetry = 0;
while (true)
{
try
{
return func();
}
catch (Exception ex) when (ex is RedisConnectionException || ex is SocketException)
{
reconnectRetry++;
if (reconnectRetry > RetryMaxAttempts)
throw;
await ForceReconnectAsync();
}
catch (ObjectDisposedException)
{
disposedRetry++;
if (disposedRetry > RetryMaxAttempts)
throw;
}
}
}
public static Task<IDatabase> GetDatabaseAsync()
{
return BasicRetryAsync(() => Connection.GetDatabase());
}
public static Task<System.Net.EndPoint[]> GetEndPointsAsync()
{
return BasicRetryAsync(() => Connection.GetEndPoints());
}
public static Task<IServer> GetServerAsync(string host, int port)
{
return BasicRetryAsync(() => Connection.GetServer(host, port));
}
Provádění příkazů mezipaměti
V souboru Program.cs přidejte pro proceduru Program třídy konzolové aplikace Main následující kód:
static void Main(string[] args)
{
InitializeConfiguration();
IDatabase cache = GetDatabase();
// Perform cache operations using the cache object...
// Simple PING command
string cacheCommand = "PING";
Console.WriteLine("\nCache command : " + cacheCommand);
Console.WriteLine("Cache response : " + cache.Execute(cacheCommand).ToString());
// Simple get and put of integral data types into the cache
cacheCommand = "GET Message";
Console.WriteLine("\nCache command : " + cacheCommand + " or StringGet()");
Console.WriteLine("Cache response : " + cache.StringGet("Message").ToString());
cacheCommand = "SET Message \"Hello! The cache is working from a .NET Core console app!\"";
Console.WriteLine("\nCache command : " + cacheCommand + " or StringSet()");
Console.WriteLine("Cache response : " + cache.StringSet("Message", "Hello! The cache is working from a .NET Core console app!").ToString());
// Demonstrate "SET Message" executed as expected...
cacheCommand = "GET Message";
Console.WriteLine("\nCache command : " + cacheCommand + " or StringGet()");
Console.WriteLine("Cache response : " + cache.StringGet("Message").ToString());
// Get the client list, useful to see if connection list is growing...
// Note that this requires allowAdmin=true in the connection string
cacheCommand = "CLIENT LIST";
Console.WriteLine("\nCache command : " + cacheCommand);
var endpoint = (System.Net.DnsEndPoint)GetEndPoints()[0];
IServer server = GetServer(endpoint.Host, endpoint.Port);
ClientInfo[] clients = server.ClientList();
Console.WriteLine("Cache response :");
foreach (ClientInfo client in clients)
{
Console.WriteLine(client.Raw);
}
CloseConnection(lazyConnection);
}
Soubor Program.cs uložte.
Azure Cache for Redis má konfigurovatelný počet databází (výchozí hodnota je 16), které lze použít k logickému oddělení dat v rámci Azure Cache for Redis. Kód se připojí k výchozí databázi DB 0. Další informace najdete v tématu Co jsou databáze Redis? a Výchozí konfigurace serveru Redis.
Položky v mezipaměti lze ukládat a načítat pomocí metod StringSet a StringGet.
Redis ukládá většinu dat jako řetězce Redis, ale tyto řetězce mohou obsahovat mnoho typů dat, včetně serializovaných binárních dat, která lze použít při ukládání objektů .NET v mezipaměti.
Vytvořte aplikaci spuštěním následujícího příkazu v okně příkazového řádku:
dotnet build
Potom aplikaci tímto příkazem spusťte:
dotnet run
V níže uvedeném příkladu můžete vidět, že klíč Message měl předtím hodnotu z mezipaměti, která byla nastavena pomocí konzoly Redis na webu Azure Portal. Aplikace tuto hodnotu z mezipaměti aktualizovala. Aplikace rovněž spustila příkazy PING a CLIENT LIST.

Práce s objekty .NET v mezipaměti
Azure Cache for Redis do mezipaměti objekty .NET i primitivní datové typy, ale před objektem .NET lze ukládat do mezipaměti, musí být serializován. Serializaci objektů .NET má na starosti vývojář aplikace, kterému je tak poskytnuta flexibilita při výběru serializátoru.
Jeden snadný způsob, jak serializovat objekty, je použít metody serializace JsonConvert v balíčku Newtonsoft.Json a serializovat a deserializovat tak objekty do a z formátu JSON. V této části přidáte do mezipaměti objekt .NET.
Spuštěním následujícího příkazu přidejte do aplikace balíček Newtonsoft.json:
dotnet add package Newtonsoft.json
Na začátek souboru Program.cs přidejte následující příkaz using:
using Newtonsoft.Json;
Do souboru Program.cs přidejte následující definici třídy Employee:
class Employee
{
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Employee(string employeeId, string name, int age)
{
Id = employeeId;
Name = name;
Age = age;
}
}
Na konec procedury Main() a před volání metody CloseConnection() v souboru Program.cs přidejte do mezipaměti následující řádky kódu a získejte serializovaný objekt .NET:
// Store .NET object to cache
Employee e007 = new Employee("007", "Davide Columbo", 100);
Console.WriteLine("Cache response from storing Employee .NET object : " +
cache.StringSet("e007", JsonConvert.SerializeObject(e007)));
// Retrieve .NET object from cache
Employee e007FromCache = JsonConvert.DeserializeObject<Employee>(cache.StringGet("e007"));
Console.WriteLine("Deserialized Employee .NET object :\n");
Console.WriteLine("\tEmployee.Name : " + e007FromCache.Name);
Console.WriteLine("\tEmployee.Id : " + e007FromCache.Id);
Console.WriteLine("\tEmployee.Age : " + e007FromCache.Age + "\n");
Soubor Program.cs uložte a pomocí následujícího příkazu aplikaci znovu sestavte:
dotnet build
Aplikaci spusťte tímto příkazem a otestujte serializaci objektů .NET:
dotnet run

Vyčištění prostředků
Pokud budete pokračovat k dalšímu kurzu, můžete prostředky vytvořené v tomto rychlém startu zachovat a znovu je použít.
V opačném případě, pokud jste už s ukázkovou aplikací v tomto rychlém startu skončili, můžete prostředky Azure vytvořené v tomto rychlém startu odstranit, abyste se vyhnuli poplatkům.
Důležité
Odstranění skupiny prostředků je nevratné a skupina prostředků včetně všech v ní obsažených prostředků bude trvale odstraněna. Ujistěte se, že nechtěně neodstraníte nesprávnou skupinu prostředků nebo prostředky. Pokud jste vytvořili prostředky pro hostování této ukázky v existující skupině prostředků, která obsahuje prostředky, které chcete zachovat, můžete místo odstranění skupiny prostředků odstranit každý prostředek jednotlivě na levé straně.
Přihlaste se k webu Azure Portal a potom vyberte Skupiny prostředků.
Do textového pole Filtrovat podle názvu zadejte název vaší skupiny prostředků. V pokynech v tomto článku se používala skupina prostředků TestResources. V seznamu výsledků ve vaší skupině prostředků vyberte ... a pak Odstranit skupinu prostředků.

Zobrazí se výzva k potvrzení odstranění skupiny prostředků. Potvrďte to tak, že zadejte název vaší skupiny prostředků, a vyberte Odstranit.
Po chvíli bude skupina prostředků včetně všech obsažených prostředků odstraněná.
Další kroky
V tomto rychlém startu jste zjistili, jak používat Azure Cache for Redis z aplikace .NET Core. Pokračujte k dalšímu rychlému startu a Azure Cache for Redis s ASP.NET aplikací.
Chcete optimalizovat útratu v cloudu a ušetřit ji?