Dela via


Riktlinjer för bakåtkompatibilitet

Att skriva bakåtkompatibel kod kan vara svårt och svårt att testa. I den här artikeln beskrivs riktlinjer för att skriva bakåtkompatibel kod i .NET Orleans. Den täcker användningen av VersionAttribute och ObsoleteAttribute.

Ändra aldrig signaturen för befintliga metoder

På grund av hur Orleans serialiseraren fungerar bör du aldrig ändra signaturen för befintliga metoder.

Följande exempel är korrekt:

[Version(1)]
public interface IMyGrain : IGrainWithIntegerKey
{
    // First method
    Task MyMethod(int arg);
}
[Version(2)]
public interface IMyGrain : IGrainWithIntegerKey
{
    // Method inherited from V1
    Task MyMethod(int arg);

    // New method added in V2
    Task MyNewMethod(int arg, obj o);
}

Det här exemplet är felaktigt:

[Version(1)]
public interface IMyGrain : IGrainWithIntegerKey
{
    // First method
    Task MyMethod(int arg);
}
[Version(2)]
public interface IMyGrain : IGrainWithIntegerKey
{
    // Method inherited from V1
    Task MyMethod(int arg, obj o);
}

Viktig

Gör INTE denna ändring i din kod, eftersom det är ett exempel på en dålig praxis som leder till mycket dåliga biverkningar.

Det här är ett exempel på vad som kan hända om du bara byter namn på parameternamnen. Anta att du har följande två gränssnittsversioner distribuerade i klustret:

[Version(1)]
public interface IMyGrain : IGrainWithIntegerKey
{
    // return a - b
    Task<int> Subtract(int a, int b);
}
[Version(2)]
public interface IMyGrain : IGrainWithIntegerKey
{
    // return b - a
    Task<int> Subtract(int b, int a);
}

Dessa metoder verkar identiska. Men om klienten anropar med V1 och en V2-aktivering hanterar begäran:

var grain = client.GetGrain<IMyGrain>(0);
var result = await grain.Subtract(5, 4); // Will return "-1" instead of expected "1"

Detta händer på grund av hur den interna Orleans serialiseraren fungerar.

Undvik att ändra befintlig metodlogik

Det kan verka uppenbart, men var mycket försiktig när du ändrar brödtexten för en befintlig metod. Om du inte åtgärdar en bugg är det bättre att lägga till en ny metod om du behöver ändra koden.

Exempel:

// V1
public interface MyGrain : IMyGrain
{
    // First method
    Task MyMethod(int arg)
    {
        SomeSubRoutine(arg);
    }
}
// V2
public interface MyGrain : IMyGrain
{
    // Method inherited from V1
    // Do not change the body
    Task MyMethod(int arg)
    {
        SomeSubRoutine(arg);
    }

    // New method added in V2
    Task MyNewMethod(int arg)
    {
        SomeSubRoutine(arg);
        NewRoutineAdded(arg);
    }
}

Ta inte bort metoder från korngränssnitt

Om du inte är säker på att de inte längre används ska du inte ta bort metoder från korngränssnittet. Om du vill ta bort metoder gör du det i två steg:

  1. Distribuera V2-korn med V1-metoden markerad som Obsolete.

    [Version(1)]
    public interface IMyGrain : IGrainWithIntegerKey
    {
        // First method
        Task MyMethod(int arg);
    }
    
    [Version(2)]
    public interface IMyGrain : IGrainWithIntegerKey
    {
        // Method inherited from V1
        [Obsolete]
        Task MyMethod(int arg);
    
        // New method added in V2
        Task MyNewMethod(int arg, obj o);
    }
    
  2. När du är säker på att inga V1-anrop görs (i praktiken distribueras V1 inte längre i klustret som körs) distribuerar du V3 med V1-metoden borttagen.

    [Version(3)]
    public interface IMyGrain : IGrainWithIntegerKey
    {
        // New method added in V2
        Task MyNewMethod(int arg, obj o);
    }