Abwärtskompatibilitätsrichtlinien

Das Schreiben von abwärtskompatiblem Code kann kompliziert und schwierig zu testen sein. In diesem Artikel werden die Richtlinien zum Schreiben von abwärtskompatiblem Code in .NET Orleans erläutert. In diesem Artikel wird die Verwendung von VersionAttribute und ObsoleteAttribute behandelt.

Ändern Sie niemals die Signatur vorhandener Methoden

Aufgrund der Funktionsweise des Orleans-Serialisierungsmoduls sollten Sie niemals die Signatur vorhandener Methoden ändern.

Das folgende Beispiel ist richtig:

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

Dieses Beispiel ist nicht richtig:

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

Wichtig

Sie sollten diese Änderung nicht in Ihrem Code vornehmen, da sie ein Beispiel für eine Methode mit sehr ungünstigen Nebenwirkungen darstellt. Dies ist ein Beispiel dafür, was passieren kann, wenn Sie nur die Parameternamen ändern: Nehmen wir an, es werden die beiden folgenden Schnittstellenversionen im Cluster bereitgestellt:

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

Diese Methoden scheinen identisch zu sein. Wenn der Client jedoch mit V1 aufgerufen und die Anforderung von einer V2-Aktivierung verarbeitet wird, geschieht Folgendes:

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

Dies ist auf die Funktionsweise des internen Orleans-Serialisierungsmoduls zurückzuführen.

Vermeiden Sie das Ändern vorhandener Methodenlogik

Es mag offensichtlich erscheinen, aber Sie sollten sehr vorsichtig sein, wenn Sie den Text einer vorhandenen Methode ändern. Sofern Sie keinen Fehler beheben, sollten Sie einfach eine neue Methode hinzuzufügen, wenn Sie den Code ändern müssen.

Beispiel:

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

Entfernen Sie keine Methoden aus Grainschnittstellen

Sie sollten Methoden nur dann aus der Grainschnittstelle entfernen, wenn Sie ganz sicher sind, dass sie nicht mehr verwendet werden. Wenn Sie Methoden entfernen möchten, sollte dies in zwei Schritten erfolgen:

  1. Stellen Sie V2-Grains bereit, wobei die V1-Methode als Obsolete gekennzeichnet ist.

    [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. Wenn Sie sicher sind, dass keine V1-Aufrufe ausgeführt werden (V1 wird effektiv nicht mehr im ausgeführten Cluster bereitgestellt), stellen Sie V3 mit entfernter V1-Methode bereit.

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