Description
The Per-Grain-class Request Interceptors feature, merged in pull request #965, allows users to override the Grain.Invoke method to perform request interception on a per-grain-class level. This feature enables developers to execute custom logic before and after a grain call, modifying the request context, arguments, and return values as needed.
public class InterceptRequestGrain : Grain, ISomeGrain
{
protected override Task Invoke(InvokeMethodRequest request, IGrainMethodInvoker invoker)
{
RequestContext.Set("InterceptedValue", 74);
return base.Invoke(request, invoker);
}
// Other methods...
}
In this example, the InterceptRequestGrain class overrides the Invoke method to set a value in the request context before calling the base Invoke method.
Grain Call Filters:
Grain call filters provide a way to intercept grain calls, executing code before and after the call. There are two types of filters:
- Incoming Call Filters: Executed when receiving a call.
- Outgoing Call Filters: Executed when making a call.
You can implement grain call filters by creating classes that implement IIncomingGrainCallFilter or IOutgoingGrainCallFilter interfaces.
Example of Incoming Grain Call Filter:
public class LoggingCallFilter : IIncomingGrainCallFilter
{
private readonly Logger _logger;
public LoggingCallFilter(Factory<string, Logger> loggerFactory)
{
_logger = loggerFactory(nameof(LoggingCallFilter));
}
public async Task Invoke(IIncomingGrainCallContext context)
{
try
{
await context.Invoke();
var msg = string.Format("{0}.{1}({2}) returned value {3}", context.Grain.GetType(), context.InterfaceMethod.Name, string.Join(", ", context.Arguments), context.Result);
_logger.Info(msg);
}
catch (Exception exception)
{
var msg = string.Format("{0}.{1}({2}) threw an exception: {3}", context.Grain.GetType(), context.InterfaceMethod.Name, string.Join(", ", context.Arguments), exception);
_logger.Info(msg);
throw;
}
}
}
This filter logs information about grain method invocations, including the method name, arguments, and return values.
Registering Grain Call Filters:
You can register grain call filters using Dependency Injection. Here's an example:
siloHostBuilder.AddIncomingGrainCallFilter();
This registers the LoggingCallFilter class as an incoming grain call filter ¹.