Usually, it's recommended to create a wrapper implementing IHttpClient
or IHttpClientFactory
. Meanwhile, some Orleans samples show that it's ok to create HttpClient
instance on-demand and use it directly from the grain.
Questions
IHttpClient
or call HttpClient directly from the grain?GrainService
and GrainServiceClient
?public interface IRemoteGrainService : IGrainService
{
Task<T> Get<T>(string source) where T : new();
}
public class RemoteGrainService : GrainService, IRemoteGrainService
{
private IGrainFactory _grainFactory;
private HttpClient _remoteService;
public RemoteGrainService(
IServiceProvider services,
IGrainIdentity id,
Silo silo,
ILoggerFactory
loggerFactory,
IGrainFactory grainFactory) : base(id, silo, loggerFactory)
{
_grainFactory = grainFactory;
}
public override Task Init(IServiceProvider serviceProvider)
{
return base.Init(serviceProvider);
}
public override async Task Start()
{
_remoteService = new HttpClient();
await base.Start();
}
public override Task Stop()
{
_remoteService.Dispose();
return base.Stop();
}
public Task<T> Get<T>(string source) where T : new()
{
return JsonConvert
.DeserializeObject<T>(
await _client.GetAsync(source))
.Content
.ReadAsStringAsync);
}
}
You should follow standard best-practices when using HttpClient
within Orleans. The sample is creating a new one for simplicity of exposition, not as an indicator of best practices. A PR to change the sample documentation to use IHttpClientFactory
(for example) would likely be accepted.
You do not need a GrainService
to call into HTTP services from your grain: you can inject the required dependencies (IHttpClientFactory
or your typed client) and call HTTP services directly from grain code.
Regarding the question on the purpose of GrainService
and GrainServiceClient
, GrainService
is a special service which is intended to be accessed from grain code. GrainServices
are instantiated on every node in the cluster and each one is given responsibility over a set of grains. As an example, reminders (persistent timers) in Orleans are implemented using GrainService
s. The LocalReminderService
on each node takes responsibility for a set of grains and will wake those grains up when their reminders are due. GrainServiceClient
is used by grains to access the GrainService
instance which is responsible for the calling grain. The documentation explains more here: https://dotnet.github.io/orleans/Documentation/grains/grainservices.html
I would avoid using GrainService
unless you find a use case which it fits closely.