artganify
artganify

Reputation: 703

Access generic type of requested service for parameter construction

I've got a service contract for a strongly-typed configuration:

public interface IConfigurationSource<TConfiguration> {
    TConfiguration Current { get; }
}

and an implementation based on YAML files:

public class YamlFileConfigurationSource<TConfiguration> 
    : IConfigurationSource<TConfiguration> {

    public YamlFileConfigurationSource(string fileName) { }

    ...
}

Now I'm trying to register the implementation within Autofac in a way that the fileName parameter can be constructed based on the generic type of the requested service. So when a client requests YamlFileConfigurationSource<MyCustomConfigurationModel> a path like MyCustomConfigurationModel.config can be provided.

I already tried with ContainerBuilder.RegisterGeneric(), .WithConstructor() and delegate factories, however I'm somehow unable to see how to access the generic type during registration.

Upvotes: 1

Views: 81

Answers (1)

Cyril Durand
Cyril Durand

Reputation: 16192

YamlFileConfigurationSource should not depends on fileName you can get it using typeof(TConfiguration)

public class YamlFileConfigurationSource<TConfiguration>
    : IConfigurationSource<TConfiguration> {

    public YamlFileConfigurationSource() { }

    public TConfiguration Current { 
        get {
            String fileName = typeof(TConfiguration).Name + ".config";
            // get config from fileName
        }
    }
}

If you want to dissociate the code where TConfiguration is converted to a fileName you can introduce a new component.

public interface IConfigurationFileProvider<TConfiguration> {
    String GetFileName(); 
}
public class SimpleConfigurationFileProvider<TConfiguration>
    : IConfigurationFileProvider<TConfiguration>  {
    public String GetFileName() {
        return typeof(TConfiguration) + ".config";
    }
}

and add this dependency on the constructor of YamlFileConfigurationSource

The registration will look like this :

builder.RegisterGeneric(typeof(YamlFileConfigurationSource<>))
        .As(typeof(IConfigurationSource<>));
builder.RegisterGeneric(typeof(SimpleConfigurationFileProvider<>))
        .As(typeof(IConfigurationFileProvider<>));

By the way, for educational purpose, this is the way to do using the WithParameter method

builder.RegisterGeneric(typeof(YamlFileConfigurationSource<>))
        .As(typeof(IConfigurationSource<>))
        .WithParameter((pi, c) => pi.Name == "fileName",
                       (pi, c) => pi.Member.DeclaringType.GetGenericArguments()[0].Name);

It should work, but it's a workaround, whereas the previous solution was more elegant.

Upvotes: 2

Related Questions