max-ieremenko / ServiceModel.Grpc

Code-first for gRPC
https://max-ieremenko.github.io/ServiceModel.Grpc/
Apache License 2.0
90 stars 11 forks source link

Is there dependency injection container support for client? #175

Closed Metadorius closed 7 months ago

Metadorius commented 9 months ago

I am using a dependency injection container on my client app and want to also register the proxies that get generated by the library as implementors of the corresponding interfaces. That way the client code would need only changed registrations in order to function. Is that currently possible? I guess MS DI abstractions would work since most of containers have support for those.

Metadorius commented 9 months ago

Another thought: considering there's source generators for proxy interface implementations, maybe it would be somehow possible to annotate the generated classes. I am using MEF attributes and for my classes I prepend something like this:

    [Export] // exports Transient
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class SomeClass {}

Then the DI container automatically registers it while scanning the assembly. Would be great if there was a possibility to add custom attributes to source generated files.

max-ieremenko commented 9 months ago

Is there dependency injection container support for client?

ServiceModel.Grpc provides a simple concept for creating proxies - ClientFactory. Unfortunately, the user can be of little help with DI as there are many variations.

// choose your DI framework
var services = new ServiceCollection();

services.AddSingleton<IClientFactory>(provider =>
{
    var factory = new ClientFactory(new ServiceModelGrpcClientOptions
    {
        // setup your configuration
        ServiceProvider = provider
        ... = ...
    });

    // setup your configuration
    factory.AddClient<IMyService1>(options => { ... });
    // setup your configuration
    factory.AddClient<IMyService2>(options => { ... });

    return factory;
});

AddGrpcProxy<IMyService1>();
AddGrpcProxy<IMyService2>();

static IServiceCollection AddGrpcProxy<T>(this IServiceCollection services)
{
    services.AddTransient<T>(provider =>
    {
        // please provide the channel
        ChannelBase channel = ... // as an option: provider.GetRequiredService<ChannelBase>();

        var clientFactory = provider.GetRequiredService<IClientFactory>();
        return clientFactory.CreateClient<T>(channel);
    });
}

As you can see from this trivial example, the user made a lot of decisions:

Would be great if there was a possibility to add custom attributes to source generated files.

How can this help with MEF, could you give a more detailed example?

Metadorius commented 9 months ago

I see, ideally the proxies would be registrated automatically in the container for whatever gRPC contract is created, like they can be created from factory using Reflection.Emit without registering them beforehand (at least per readme example that's how it happens).

How can this help with MEF, could you give a more detailed example?

It's pretty simple, I am not sure how to detail it for you. Using MEF attributes like the ones in my reply above (in my case with DryIoc, see here) I just annotate whatever classes I need to register in the container, like my DAO and in this case I would want to annotate my proxies with attributes that tell "yo, this class has to be registered as an implementor of that interface". I then call a function to register assembly types that are marked with attributes and get all the annotated stuff registered automatically. Maybe you could ask some specific details so I can clarify it further?

max-ieremenko commented 9 months ago

I will put MS DI on my to-do list. Will it be an example or an API with example, we'll see.

Regarding MEF and custom attributes in generated code. Would you mind creating an example to demonstrate how this might look and work?

max-ieremenko commented 8 months ago

Extensions for Microsoft.DependencyInjection and Grpc.Net.ClientFactory are released in version 1.7.0: new nuget package ServiceModel.Grpc.Client.DependencyInjection, see example ClientDependencyInjection.

Metadorius commented 8 months ago

Thanks much and sorry for not getting back to that, had to switch to different tasks urgently at that moment. If there's still a need I'll detail it more when I get back to client-server stuff in our project.

max-ieremenko commented 7 months ago

Since no activity, I am closing this issue. If this is in error, let me know with a comment.