Расширения зерна
Расширения зерна предоставляют способ добавления дополнительного поведения к зернам. Расширяя зерно с интерфейсом, производным от IGrainExtension, можно добавить новые методы и функциональные возможности к зерне.
В этой статье вы увидите два примера расширений зерна. В первом примере показано, как добавить Deactivate
метод ко всем зернам, которые можно использовать для деактивации зерна. Во втором примере показано, как добавить GetState
и SetState
метод к любому зерне, что позволяет управлять внутренним состоянием зерна.
Пример деактивации расширения
В этом примере вы узнаете, как автоматически добавить Deactivate
метод ко всем зернам. Этот метод можно использовать для деактивации зерна и принятия строки в качестве параметра сообщения. Orleans зерна уже поддерживают эту функцию через IGrainManagementExtension интерфейс. Тем не менее, в этом примере показано, как можно добавить эту или аналогичную функциональность самостоятельно.
Деактивация интерфейса расширения
Сначала определите IGrainDeactivateExtension
интерфейс, содержащий Deactivate
метод. Интерфейс должен быть производным от IGrainExtension
.
public interface IGrainDeactivateExtension : IGrainExtension
{
Task Deactivate(string msg);
}
Деактивация реализации расширения
Затем реализуйте GrainDeactivateExtension
класс, который предоставляет реализацию для Deactivate
метода.
Чтобы получить доступ к целевому зерню, извлекается IGrainContext
из конструктора. Он внедряется при создании расширения с внедрением зависимостей.
public sealed class GrainDeactivateExtension : IGrainDeactivateExtension
{
private IGrainContext _context;
public GrainDeactivateExtension(IGrainContext context)
{
_context = context;
}
public Task Deactivate(string msg)
{
var reason = new DeactivationReason(DeactivationReasonCode.ApplicationRequested, msg);
_context.Deactivate(reason);
return Task.CompletedTask;
}
}
Отключение регистрации и использования расширений
Теперь, когда вы определили интерфейс и реализацию, зарегистрируйте расширение при настройке сило с AddGrainExtension помощью метода.
siloBuilder.AddGrainExtension<IGrainDeactivateExtension, GrainDeactivateExtension>();
Чтобы использовать расширение для любого зерна, получите ссылку на расширение и вызовите Deactivate
метод.
var grain = client.GetGrain<SomeExampleGrain>(someKey);
var grainReferenceAsInterface = grain.AsReference<IGrainDeactivateExtension>();
await grainReferenceAsInterface.Deactivate("Because, I said so...");
Пример расширения управления состоянием
В этом примере вы узнаете, как добавить GetState
и SetState
метод к любому зерне через расширения, что позволяет управлять внутренним состоянием зерна.
Интерфейс расширения управления состоянием
Сначала определите IGrainStateAccessor<T>
интерфейс, содержащий GetState
и SetState
методы. Опять же, этот интерфейс должен быть производным от IGrainExtension
.
public interface IGrainStateAccessor<T> : IGrainExtension
{
Task<T> GetState();
Task SetState(T state);
}
Получив доступ к целевому зерню, вы можете использовать расширение для управления его состоянием. В этом примере вы используете расширение для доступа и изменения определенного целочисленного значения состояния в целевом зерне.
Реализация расширения управления состоянием
Используется IGrainStateAccessor<T>
расширение, которое предоставляет методы для получения и задания значения состояния типа T
. Чтобы создать расширение, вы реализуете интерфейс в классе, который принимает и getter
в setter
качестве аргументов в его конструкторе.
public sealed class GrainStateAccessor<T> : IGrainStateAccessor<T>
{
private readonly Func<T> _getter;
private readonly Action<T> _setter;
public GrainStateAccessor(Func<T> getter, Action<T> setter)
{
_getter = getter;
_setter = setter;
}
public Task<T> GetState()
{
return Task.FromResult(_getter.Invoke());
}
public Task SetState(T state)
{
_setter.Invoke(state);
return Task.CompletedTask;
}
}
В предыдущей реализации GrainStateAccessor<T>
класс принимает getter
и setter
аргументы в конструкторе. Эти делегаты используются для чтения и изменения состояния целевого зерна. Метод GetState()
возвращает текущее значение T
состояния, а SetState(T state)
метод задает Task<TResult> новое значение T
состояния.
Регистрация и использование расширения управления состоянием
Чтобы использовать расширение для доступа и изменения состояния целевого зерна, необходимо зарегистрировать расширение и задать его компоненты в Grain.OnActivateAsync() методе целевого зерна.
public override Task OnActivateAsync()
{
// Retrieve the IGrainStateAccessor<T> extension
var accessor = new GrainStateAccessor<int>(
getter: () => this.Value,
setter: value => this.Value = value);
// Set the extension as a component of the target grain's context
((IGrainBase)this).GrainContext.SetComponent<IGrainStateAccessor<int>>(accessor);
return base.OnActivateAsync();
}
В приведенном выше примере создается новый экземпляр GrainStateAccessor<int>
, который принимает getter
значение и setter
целочисленное значение состояния. Объект getter
считывает Value
свойство целевого зерна, а setter
задает новое значение Value
свойства. Затем этот экземпляр устанавливается в качестве компонента контекста целевого зерна с помощью IGrainContext.SetComponent метода.
После регистрации расширения его можно использовать для получения и задания состояния целевого зерна путем доступа к нему через ссылку на расширение.
// Get a reference to the IGrainStateAccessor<int> extension
var accessor = grain.AsReference<IGrainStateAccessor<int>>();
// Get the current value of the state
var value = await accessor.GetState();
// Set a new value of the state
await accessor.SetState(10);
В предыдущем примере вы получите ссылку на IGrainStateAccessor<int>
расширение для конкретного экземпляра зерна с помощью GrainExtensions.AsReference метода. Затем эту ссылку можно использовать для вызова GetState()
и SetState(T state)
методов для чтения и изменения значения состояния целевого зерна.