Dynamically adding a Service with a Generic by an Activator?

89 views Asked by At

Ok, the Title already sounds a bit silly, but I don't even know how to describe this better. So let's try to outline the problem.

What I've figured out so far is the following, which is working:

Given I have an interface like that

public interface ISomeService {}

then I can dynamically add the service with it's implementation like that

var vendorService = assembly?.GetType($"{vendor}.Services.{vendor}Service");

// null-check here

services.TryAddSingleton<ISomeService>(_ =>
   (ISomeService) Activator.CreateInstance(vendorService, _config)!);

(I need to do this, because at Compile-time I do not yet know which service will be finally loaded. This information is coming from a command-line-argument)

So far so good...

Now I have another Service that looks like this:

public interface IInformationService<T>
{
    public string? Serialize(T vendorInformation, bool isFile);

    public T Deserialize(string? filename = null);
}

In this case I don't know how to add the Service to a collection since...

var vendorInfoService = assembly?.GetType($"{vendor}.Services.InformationService<{vendor}>");

// null-check here

services.TryAddSingleton<IInformationService< [???] >>(_ =>
   (IInformationService< [???] >) Activator.CreateInstance(vendorInfoService, _config)!);

... I don't know how to pass T down, which is not known until it is clear what vendor is.

So given the vendor (which is not known at compile-time) is "Foo" then the actual Type of the above vendorService would be FooService, the Information-Service would be InformationService<FooModel>.

But I'm really not sure how to implement it.

Maybe you can help me out. Thanks in advance :)

1

There are 1 answers

1
t.haeusler On

That should be possible like this:

builder.Services.AddSingleton(typeof(IGenericService<>),
    p => /* do something to get service */);

or, if you want to get rid of the Activator, just like this:

var type = assembly.GetType($"Generic{vendor}Service"); // or get the type somehow
builder.Services.AddSingleton(typeof(IGenericService<>), type);

The problem here is, that you don't get any information about the "T", so you somehow have to make sure that for every T you try to inject in one of your services, there is a binding that matches said T.

A better way would most likely be to reiterate over this and define a service interface without the generic and design an IVendorInformationModel instead, which is passed to Serialize or provided by Deserialize.