Grpc: .net core 2.0 grpc support dependency injection?

Created on 11 Sep 2017  路  3Comments  路  Source: grpc/grpc

Hi,

I'm using .net core 2.0 Grpc Version 1.6.0.
I'm trying to use Dependency Injection with Transient/Scoped/Singleton in my implementation.
But I found there are some issues during concurrent request come in.
The thread no longer safe. For example, IDbConnection keep reusing by another thread, which end up error like:

  1. Connection must be valid and open.
  2. Object reference not set to an instance of an object.
  3. There is already an open DataReader associated with this Connection which must be closed first.
  4. Value cannot be null.
  5. The given key was not present in the dictionary.
  6. Probable I/O race condition detected while copying memory. The I/O package is not thread safe by default. In multithreaded applications, a stream must be accessed in a thread-safe way, such as a thread-safe wrapper returned by TextReader's or TextWriter's Synchronized methods. This also applies to classes like StreamWriter and StreamReader.

Please advise is there anyway/example showing the usage of dependency injection in grpc c# .net core 2.0?

Thanks.

Most helpful comment

As it is currently setup you can't use DI in the traditional way. The grpc classes where your methods for handling requests are located are created once when passed to the server and then used for all incoming requests resulting in anything injected into those classes acting like a singleton.

If you want to use DI you could set it up similar to this:

Create your service provider and add services:

var collection = new ServiceCollection();
collection.AddScoped<ITest, Test>();
collection.AddTransient<ITestTwo, TestTwo>();
var provider = collection.BuildServiceProvider();

Add the service provider to CTOR of your grpc class (HelloWorld example in this case). For each request create a scoped provider and manually resolve classes needed from there:

class GreeterImpl : Greeter.GreeterBase
{
    private IServiceProvider _provider;

    public GreeterImpl(IServiceProvider provider)
    {
        _provider = provider;
    }
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        var scoped = _provider.CreateScope();
        var mytest = scoped.ServiceProvider.GetRequiredService<ITest>();
        var mytesttwo = scoped.ServiceProvider.GetRequiredService<ITestTwo>();
        //use "injected" classes...
        return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
    }
}

When you create your Server just pass the provider with the class to the server:

Server server = new Server
{
    Services = { Greeter.BindService(new GreeterImpl(provider)) },
}

This assumes that IServiceProvider is thread safe. Looking at the source it appears to be implemented using a ConcurrentDictionary (https://github.com/aspnet/DependencyInjection/blob/dev/src/DI/ServiceLookup/ServiceProviderEngine.cs) so this is likely true.

I've been looking at a more elegant way to accomplish this automatically without killing performance but it's difficult with how things are currently implemented.

All 3 comments

As it is currently setup you can't use DI in the traditional way. The grpc classes where your methods for handling requests are located are created once when passed to the server and then used for all incoming requests resulting in anything injected into those classes acting like a singleton.

If you want to use DI you could set it up similar to this:

Create your service provider and add services:

var collection = new ServiceCollection();
collection.AddScoped<ITest, Test>();
collection.AddTransient<ITestTwo, TestTwo>();
var provider = collection.BuildServiceProvider();

Add the service provider to CTOR of your grpc class (HelloWorld example in this case). For each request create a scoped provider and manually resolve classes needed from there:

class GreeterImpl : Greeter.GreeterBase
{
    private IServiceProvider _provider;

    public GreeterImpl(IServiceProvider provider)
    {
        _provider = provider;
    }
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        var scoped = _provider.CreateScope();
        var mytest = scoped.ServiceProvider.GetRequiredService<ITest>();
        var mytesttwo = scoped.ServiceProvider.GetRequiredService<ITestTwo>();
        //use "injected" classes...
        return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
    }
}

When you create your Server just pass the provider with the class to the server:

Server server = new Server
{
    Services = { Greeter.BindService(new GreeterImpl(provider)) },
}

This assumes that IServiceProvider is thread safe. Looking at the source it appears to be implemented using a ConcurrentDictionary (https://github.com/aspnet/DependencyInjection/blob/dev/src/DI/ServiceLookup/ServiceProviderEngine.cs) so this is likely true.

I've been looking at a more elegant way to accomplish this automatically without killing performance but it's difficult with how things are currently implemented.

Hi Michael Plaisted,

Implemented your solution. It's WORKING fine now!
Thanks.

@GoldwinLeong You could take a look my example here:
https://github.com/m-andrei/grpc-example-for-.net-core/blob/master/Grpc.Example.Server/GrpcServerExtentions.cs#L18
but it will work properly only for Singleton and Transient lifetimes, It was enough for my purposes.
To implement Scoped lifeTime need to add some logic into grpc server interceptor.

Was this page helpful?
0 / 5 - 0 ratings