Snabbstart: Använda Azure Cache for Redis i .NET Framework

I den här snabbstarten införlivar du Azure Cache for Redis i en .NET Framework-app för att få åtkomst till en säker, dedikerad cache som kan nås från alla program i Azure. Du använder specifikt StackExchange.Redis-klienten med C#-kod i en .NET-konsolapp.

Hoppa till koden på GitHub

Om du vill hoppa direkt till koden kan du gå .NET Framework snabbstarten på GitHub.

Förutsättningar

Skapa en cache

  1. Om du vill skapa en cache loggar du in på Azure Portal och väljer skapa en resurs.

    Skapa en resurs markeras i det vänstra navigerings fönstret.

  2. Välj databaser på sidan nytt och välj sedan Azure cache för Redis.

    På nytt markeras databaser och Azure cache för Redis är markerat.

  3. På sidan ny Redis cache konfigurerar du inställningarna för din nya cache.

    Inställning Föreslaget värde Beskrivning
    DNS-namn Ange ett globalt unikt namn. Cache-namnet måste vara en sträng mellan 1 och 63 tecken som bara innehåller siffror, bokstäver eller bindestreck. Namnet måste börja och sluta med en siffra eller en bokstav och får inte innehålla flera bindestreck i rad. Din cacheposts värdnamn är <DNS name> . Redis.cache.Windows.net.
    Prenumeration List rutan och välj din prenumeration. Den prenumeration som du vill skapa den här nya Azure-cache för Redis-instansen för.
    Resursgrupp List rutan och välj en resurs grupp, eller Välj Skapa ny och ange ett nytt resurs grupp namn. Namnet på resurs gruppen där du vill skapa cachen och andra resurser. Genom att lägga till alla dina app-resurser i en resurs grupp kan du enkelt hantera eller ta bort dem tillsammans.
    Plats List rutan och välj en plats. Välj en region nära andra tjänster som ska använda din cache.
    Prisnivå List rutan och välj en pris nivå. Prisnivån avgör storlek, prestanda och funktioner som är tillgängliga för cacheminnet. Mer information finns i Översikt över Azure Cache for Redis.
  4. Välj fliken nätverk eller klicka på knappen nätverk längst ned på sidan.

  5. På fliken nätverk väljer du anslutnings metod.

  6. Välj Nästa: fliken Avancerat eller klicka på Nästa: Avancerat längst ned på sidan.

  7. På fliken Avancerat för en Basic-eller standard-cachepost väljer du aktivera växling om du vill aktivera en icke-TLS-port. Du kan också välja vilken Redis-version du vill använda, antingen 4 eller (för hands version) 6.

    Redis-version 4 eller 6.

  8. På fliken Avancerat för Premium-cache-instans konfigurerar du inställningarna för icke-TLS-port, klustring och data beständighet. Du kan också välja vilken Redis-version du vill använda, antingen 4 eller (för hands version) 6.

  9. Välj fliken Nästa: Taggar eller klicka på knappen Nästa: Taggar längst ned på sidan.

  10. Alternativt går du till fliken taggar och anger namn och värde om du vill kategorisera resursen.

  11. Välj Granska + skapa. Du kommer till fliken Granska + skapa där Azure verifierar konfigurationen.

  12. När meddelandet grön verifiering har skickats visas väljer du skapa.

Det tar en stund innan cacheminnet skulle skapas. Du kan övervaka förloppet på översikts sidan för Azure-cache för Redis. När statusen är igång är cacheminnet redo att användas.

Hämta värdnamn, portar och åtkomst nycklar från Azure Portal

För att ansluta till en Azure-cache för Redis-instansen behöver cache-klienterna värd namnet, portarna och en nyckel för cachen. Vissa klienter kan hänvisa till dessa objekt med namn som skiljer sig något. Du kan hämta värdnamn, portar och nycklar från Azure Portal.

  • Hämta åtkomst nycklarna genom att gå till vänster navigering i cachen och välja åtkomst nycklar.

    Nycklar för Azure Cache for Redis

  • För att hämta värd namnet och portarna, från din cache-vänstra navigering, väljer du Egenskaper. Värd namnet är av formatet <DNS name> . Redis.cache.Windows.net.

    Egenskaper för Azure Cache for Redis

Skapa en fil på datorn med namnet CacheSecrets.config och placera den på en plats där den inte checkas in med källkoden för exempelappen. För den här snabbstarten finns filen CacheSecrets.config här: C:\AppSecrets\CacheSecrets.config.

Redigera filen CacheSecrets.config och lägg till följande innehåll:

<appSettings>
    <add key="CacheConnection" value="<host-name>,abortConnect=false,ssl=true,allowAdmin=true,password=<access-key>"/>
</appSettings>

Ersätt <host-name> med din cachens värdnamn.

Ersätt <access-key> med primärnyckeln för cachen.

Skapa en konsolapp

I Visual Studio väljer du Arkiv > > ny Project.

Välj Konsolapp (.NET Framework) och Nästa för att konfigurera din app. Ange ett Project, kontrollera att .NET Framework 4.6.1 eller senare har valts och välj sedan Skapa för att skapa ett nytt konsolprogram.

Konfigurera cacheklienten

I det här avsnittet konfigurerar du konsolprogrammet att använda StackExchange.Redis-klienten för .NET.

I Visual Studio väljer du Verktyg NuGet Package Manager Package Manager Console och kör > > följande kommando från package manager-konsolfönstret.

Install-Package StackExchange.Redis

När installationen är klar är StackExchange.Redis-cacheklienten tillgänglig för användning med ditt projekt.

Ansluta till cachen

Öppna din App.config-fil i Visual Studio och uppdatera den så att den inlkuderar ett appSettings file-attribut som refererar till filen CacheSecrets.config.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>

    <appSettings file="C:\AppSecrets\CacheSecrets.config"></appSettings>
</configuration>

I Solution Explorer högerklickar du på Referenser och väljer Lägg till en referens. Lägg till en referens i sammansättningen System.Configuration.

Lägg till följande using-instruktioner i Program.cs:

using StackExchange.Redis;
using System.Configuration;

Anslutningen till Azure Cache for Redis hanteras av ConnectionMultiplexer-klassen. Den här klassen delas och återanvändas i hela klientprogrammet. Skapa inte en ny anslutning för varje åtgärd.

Lagra aldrig autentiseringsuppgifterna i källkoden. Om du vill hålla det här exemplet enkelt använder jag endast en config-fil för externa hemligheter. En bättre metod är att använda Azure Key Vault med certifikat.

I Program.cs, lägger du till följande medlemmar i Program-klassen för ditt konsolprogram:

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 = ConfigurationManager.AppSettings["CacheConnection"].ToString();
        return ConnectionMultiplexer.Connect(cacheConnection);
    });
}

Den här metoden för att dela en ConnectionMultiplexer-instans i ditt program använder en statisk egenskap som returnerar en ansluten instans. Koden ger ett trådsäkert sätt att endast initiera en enda ansluten ConnectionMultiplexer-instans. abortConnect är inställt på falskt, vilket innebär att anropet lyckas även om en anslutning till Azure Cache for Redis inte har etablerats. En viktig egenskap i ConnectionMultiplexer är att anslutningen till cachen återställs automatiskt när nätverksproblemet eller andra fel har åtgärdats.

Värdet för appinställningen CacheConnection används för att referera till cache-anslutningssträngen från Azure-portalen som lösenordsparameter.

Hantera RedisConnectionException och SocketException genom att ansluta igen

En rekommenderad metod när du anropar metoder på är att försöka lösa och undantag automatiskt genom att stänga och ConnectionMultiplexer RedisConnectionException återupprätta SocketException anslutningen.

Lägg till följande using-instruktioner i Program.cs:

using System.Net.Sockets;
using System.Threading;

I Program.cs lägger du till följande medlemmar i Program klassen :

private static long lastReconnectTicks = DateTimeOffset.MinValue.UtcTicks;
private static DateTimeOffset firstErrorTime = DateTimeOffset.MinValue;
private static DateTimeOffset previousErrorTime = DateTimeOffset.MinValue;

private static readonly object reconnectLock = new object();

// In general, let StackExchange.Redis handle most reconnects,
// so limit the frequency of how often ForceReconnect() will
// actually reconnect.
public static TimeSpan ReconnectMinFrequency => 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 int RetryMaxAttempts => 5;

private static void CloseConnection(Lazy<ConnectionMultiplexer> oldConnection)
{
    if (oldConnection == null)
        return;

    try
    {
        oldConnection.Value.Close();
    }
    catch (Exception)
    {
        // Example error condition: if accessing oldConnection.Value causes a connection attempt and that fails.
    }
}

/// <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 ForceReconnect().
///     2. Don't call ForceReconnect for Timeouts, just for RedisConnectionExceptions or SocketExceptions.
///     3. Call this method every time you see a connection exception. 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 "ReconnectMinFrequency"
/// </summary>
public static void ForceReconnect()
{
    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 ForceReconnect at the same time, we only want to honor one of them.
    if (elapsedSinceLastReconnect < ReconnectMinFrequency)
        return;

    lock (reconnectLock)
    {
        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 < ReconnectMinFrequency)
            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;

        Lazy<ConnectionMultiplexer> oldConnection = lazyConnection;
        CloseConnection(oldConnection);
        lazyConnection = CreateConnection();
        Interlocked.Exchange(ref lastReconnectTicks, utcNow.UtcTicks);
    }
}

// In real applications, consider using a framework such as
// Polly to make it easier to customize the retry approach.
private static T BasicRetry<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;
            ForceReconnect();
        }
        catch (ObjectDisposedException)
        {
            disposedRetry++;
            if (disposedRetry > RetryMaxAttempts)
                throw;
        }
    }
}

public static IDatabase GetDatabase()
{
    return BasicRetry(() => Connection.GetDatabase());
}

public static System.Net.EndPoint[] GetEndPoints()
{
    return BasicRetry(() => Connection.GetEndPoints());
}

public static IServer GetServer(string host, int port)
{
    return BasicRetry(() => Connection.GetServer(host, port));
}

Kör cachekommandon

Lägg till följande kod för procedur Main för klass Program för ditt konsolprogram:

static void Main(string[] args)
{
    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 console app!\"";
    Console.WriteLine("\nCache command  : " + cacheCommand + " or StringSet()");
    Console.WriteLine("Cache response : " + cache.StringSet("Message", "Hello! The cache is working from a .NET 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);
}

Azure Cache for Redis har ett konfigurerbart antal databaser (16 är standard) som kan användas för att logiskt separera data i ett Azure Cache for Redis. Koden ansluter till standarddatabasen DB 0. Mer information finns i What are Redis databases? (Vad är Redis-databaser?) och Default Redis server configuration (Standardkonfiguration av Redis-server).

Cacheobjekt kan lagras och hämtas med hjälp av metoderna StringSet och StringGet.

Redis lagrar de flesta data som Redis-strängar, men dessa strängar kan innehålla flera typer av data, inklusive serialiserade binära data som kan användas när .NET-objekt lagras i cacheminnet.

Tryck på Ctrl+F5 för att skapa och köra konsolprogrammet.

I exemplet nedan ser du att Message-nyckeln tidigare hade ett cachelagrat värde som angavs med Redis-konsolen i Azure Portal. Appen uppdatera det cachelagrade värdet. Appen körde även kommandona PING och CLIENT LIST.

Partiell konsolapp

Arbeta med .NET-objekt i cachen

Azure Cache for Redis kan cachelagra både .NET-objekt och basdatatyper, men .NET-objekt måste serialiseras innan de kan cachelagras. Den här .NET-objektserialiseringen är programutvecklarens ansvar och ger utvecklaren flexibilitet i valet av serialiserare.

Ett enkelt sätt att serialisera objekt är att använda JsonConvert-serialiseringsmetoderna i Newtonsoft.Json och serialisera till och från JSON. I det här avsnittet ska du lägga till ett .NET-objekt till cachen.

I Visual Studio väljer du Verktyg NuGet Package Manager Package Manager Console och kör > > följande kommando från package manager-konsolfönstret.

Install-Package Newtonsoft.Json

Lägg till följande using-uttryck högst upp i Program.cs:

using Newtonsoft.Json;

Lägg till följande Employee-klassdefinition i Program.cs:

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

Längst ned i Main()-procedur i Program.cs, och innan anropet till CloseConnection(), lägger du till följande rader med kod i cachen och hämtar ett serialiserat .NET-objekt:

    // 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");

Tryck på Ctrl + F5 att skapa och köra konsolappen om du vill testa serialisering av .NET-objekt.

Konsolappen har slutförts

Rensa resurser

Om du ska fortsätta till nästa självstudie kan du behålla resurserna som du har skapat i den här självstudien och använda dem igen.

Om du är klar med exempelappen för snabbstart kan du ta bort Azure-resurserna som du skapade i snabbstarten för att undvika kostnader.

Viktigt

Det går inte att ångra borttagningen av en resursgrupp och att resursgruppen och alla resurser i den tas bort permanent. Kontrollera att du inte av misstag tar bort fel resursgrupp eller resurser. Om du har skapat resurserna som är värdar för det här exemplet i en befintlig resursgrupp som innehåller resurser som du vill behålla, kan du ta bort varje resurs individuellt till vänster i stället för att ta bort resursgruppen.

Logga in på Azure Portal och välj Resursgrupper.

Skriv namnet på din resursgrupp i textrutan Filter by name... (Filtrera efter namn...). Anvisningarna för den här artikeln använde en resursgrupp med namnet TestResources. I resursgruppen i resultatlistan väljer du ... och sedan Ta bort resursgrupp.

Ta bort

Du blir ombedd att bekräfta borttagningen av resursgruppen. Skriv namnet på resursgruppen för att bekräfta och välj Ta bort.

Efter en liten stund tas resursgruppen och resurser som finns i den bort.

Nästa steg

I den här snabbstarten du har lärt dig hur du använder Azure Cache for Redis från ett .NET-program. Fortsätt till nästa snabbstart om du vill använda Azure Cache for Redis med en ASP.NET-webbapp.

Vill du optimera och spara på dina molnutgifter?