user11712184
user11712184

Reputation:

How to get all the Services from Startup.cs

How do I obtain all the services after StartupClass has run?

We have a Startup Configure Services class which runs multiple dependency injection.

 serviceCollection.AddScoped<IDepartmentRepository, DepartmentRepository>();
 serviceCollection.AddScoped<IDepartmentAppService, DepartmentAppService>();

Team is using Xunit Test Project and wants to grab all the Service collection list for Xunit.

Need services from this below:

new WebHostBuilder()
            .UseContentRoot("C:\\Test\\Test.WebAPI")
            .UseEnvironment("Development")
            .UseConfiguration(new ConfigurationBuilder()
                .SetBasePath("C:\\Test\\Test.WebAPI")
                .AddJsonFile("appsettings.json")
                .Build()).UseStartup<Startup>());

Upvotes: 1

Views: 1748

Answers (2)

felix-b
felix-b

Reputation: 8498

Services in ServiceCollection are represented by the ServiceDescriptor class. You can get a list of all service descriptors by chaining a ConfigureTestServices method to your WebHostBuilder (you have to install Microsoft.AspNetCore.TestHost package)

using Microsoft.AspNetCore.TestHost;

....

IWebHost CreateWebHost(out ServiceDescriptor[] allServices)
{
    ServiceDescriptor[] grabbedServices = null;

    var host = new WebHostBuilder()
        // ... other stuff ...
        .UseStartup<Startup>()
        // add the following call:
        .ConfigureTestServices(services => {
            // copy all service descriptors
            grabbedServices = services.ToArray(); 
        })
        // build the host now to trigger the above chain
        .Build();

    allServices = grabbedServices;
    return host;
}

It is then convenient to use like this:

[Fact]
public void TestSomething()
{
    // arrange

    var host = CreateWebHost(out var services);
    // ... do something with the services

    // act
    // assert    
}

The reason we have to use ConfigureTestServices (and not ConfigureServices) is that ConfigureServices is always invoked before the methods in the Startup class, whereas ConfigureTestServices is invoked afterward.

UPDATE

Of course, it's also possible to just store the reference to ServiceCollection in a variable/field, and enumerate the services whenever necessary.

Upvotes: 1

Maxim Zabolotskikh
Maxim Zabolotskikh

Reputation: 3367

So I understood your question that you want to test you services and have problems with loading them in test project. I'd say you don't need to. In unit tests every time you test a single service. This service you instantiate directly:

var target= new ServiceToTest();

So you reference your testED project from your test project. In case your implementation is internal, add to your testED project an AssemblyInfo.cs file and put the following inside:

[assembly: InternalsVisibleTo("MyTestProject")]

Whenever you test your MyServiceToTest1, in case it has a dependecy to MyServiceTest2, you don't have to load or instantiate MyServiceTest2. Instead you mock it, e.g. with moq.

Upvotes: 0

Related Questions