Skip to content
This repository has been archived by the owner on Nov 2, 2018. It is now read-only.

Question: How to create instance of service that has constructor parameters. #422

Closed
mhsimkin opened this issue Jun 21, 2016 · 5 comments
Closed

Comments

@mhsimkin
Copy link

Environment: .NET 4.6.1 (Not Core)

I'm trying to use the new Microsoft.Extensions.DependencyInjections classes with .NET 4.6.1.

I have that has this signature:

public class RabbitMqConnection : IMessagingConnection`
{
     public RabbitMqConnection(ILogger<RabbitMqConnection> logger, string connectionString)
     {
     }
}

In my test harness, I'm creating an instance of the ServiceCollection, registering my interface and implementation.


[TestFixture]
    public class ConnectionTests
    {
        private readonly Uri AmqpUri = new Uri("aqmp://renscribe:Helium2@dwerecrq01.hq.bn-corp.com:5672/v.pds.ren.scribe");
        private readonly string ConnectionString =
            "host=dwerecrq01.hq.bn-corp.com;port=5672;virtualHost=v.pds.ren.scribe;requestedHeartbeat=30;prefetchcount=100;timeout=12" +
            "maxScribeLocalQueue=800;scribeMessageSerializeVersion=3;maxMessageSize=4194304;maxExceptionSize=4194304;getUserOnEveryMessage=true;";

        private static IServiceProvider _services;

        [SetUp]
        public void Setup()
        {
            var serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);
            _services = serviceCollection.BuildServiceProvider();
            var lf = _services.GetRequiredService<ILoggerFactory>();
            lf.AddConsole().AddDebug();
        }

        private void ConfigureServices(IServiceCollection serviceCollection)
        {
            serviceCollection.AddLogging();
            serviceCollection.AddTransient<IMessagingConnection, RabbitMqConnection>();
        }
        [Test]
        public void Should_correctly_parse_connection_string()
        {
            var connection =
                ActivatorUtilities.CreateInstance<IMessagingConnection>(_services, ConnectionString );
                //_services.GetRequiredService<IMessagingConnection>();

            var logger = _services.GetRequiredService<ILogger<ConnectionTests>>();

            using (logger.BeginScope($"=>{nameof(Should_correctly_parse_connection_string)}"))
            {
                logger.LogInformation("Test starting");
                logger.LogInformation("Test completed");
            }
        }
    }

The call to ActivatorUtilities.CreateInstance fails with the error:

A suitable constructor for type 'bn.pds.tools.Messaging.IMessagingConnection' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.

If I remove the string parameter to the constructor, and use _services.GetRequiredService<>(), everything works as expected.

How can I create an instance of a service that requires additional parameters for the constructor?

Thanks

marc

@mhsimkin
Copy link
Author

If there are examples, documentation, kb, wiki pages available that answer my questions, please point me in the correct direction.

Thanks

@pranavkm
Copy link
Contributor

@mhsimkin
Copy link
Author

Hi, thank you for your response. I tested that approach, I still get the same error. I also changed my constructor to expect an ILoggerFactory instead of an ILogger, the same issue.

Also, if I just have my constructor expect an ILogger, and use the IServiceProvider::GetRequiredService method, my object is created, and the constructor is called.

Further, this call in my code resolves file when a Logger<> is registered:

var logger = _services.GetRequiredService<ILogger<ConnectionTests>>();

@pranavkm
Copy link
Contributor

Sorry, I just noticed your AddLogging statement. That said, the issue is here that ActivatorUtilities.CreateInstance<TVal> works similar to how Activator.CreateInstance works - it creates an instance of TVal by filling in values passed in or from the service container when there isn't an equivalent argument. In this case, you have to do Activator.CreateInstance<RabbitMqConnection>() as opposed to Activator.CreateInstance<IMessageConnection>().

@mhsimkin
Copy link
Author

thanks. that resolved the issue and made me realize, I have a design problem.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants