简体   繁体   中英

Mock call to .Net Core class library with DI

I'm having trouble creating a console program to call the enrol method in referenced class library. I cannot get the dependencies injected except the config.

The Class library contains the code to call:

public interface IMyClient
{
    Task DoSomething(Request request);
}

public class MyClient : IMyClient
{
    private readonly MyClientConfig _config;
    private readonly ILogger<MClient> _logger;
    private readonly HttpClient _client;

    public MyClient()
    {

    }

    public MyClient(MyClientConfig config, ILogger<MyClient> logger, HttpClient client)
    {
        _config = config;
        _logger = logger;
        _client = client;
    }

    public async Task DoSomething(Request request)
    {
        // BREAKPOINT HERE HAS config (id = 1) but logger & client are null
    }
}

And the console program

class Program
{
    private static IServiceProvider _serviceProvider;
    static void Main(string[] args)
    {
        RegisterServices();
        IServiceScope scope = _serviceProvider.CreateScope();

        var request = new Request()
        {
            Id = 1
        };

        scope.ServiceProvider.GetRequiredService<IMyClient>().DoSomething(request);

        DisposeServices();
    }

    private static void RegisterServices()
    {
        var myClientConfig = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", true, true)
            .Build().GetSection("MyClient").Get<MyClientConfig>();


        var services = new ServiceCollection();
        services.AddSingleton<IMyClient, MyClient>();
        services.AddSingleton<IMyClientConfig>(myClientConfig);
        _serviceProvider = services.BuildServiceProvider(true);
    }

    private static void DisposeServices()
    {
        if (_serviceProvider == null)
        {
            return;
        }
        if (_serviceProvider is IDisposable)
        {
            ((IDisposable)_serviceProvider).Dispose();
        }
    }
}

I tried adding in

services.AddSingleton<HttpClient>(new HttpClient());

to get the HttpCLient injected but to no avail.

Any help appreciated or advice on testing the call to DoSomething in the referenced project

You're not configuring your Logger and HttpClient in services . You are also likely missing an additional Nuget package, Microsoft.Extensions.Logging.Console - install that if it's missing, since you mentioned this is a Console App

Modify your code as follows:

    private static void RegisterServices()
    {

        var myClientConfig = new ConfigurationBuilder()
                                .AddJsonFile("appsettings.json", true, true)
                                .Build().GetSection("MyClient").Get<MyClientConfig>();

        var services = new ServiceCollection();
        services.AddSingleton<IMyClient, MyClient>();

        // Configure logging service
        services.AddLogging(cfg => cfg.AddConsole())
                .AddTransient<MyClient>();

        // Configure HttpClient - might need some constructor params, depending on your use case
        services.AddSingleton<HttpClient>(new HttpClient());

        _serviceProvider = services.BuildServiceProvider(true);
    }

Also, very important : remove your empty constructor in MyClient ! You never want that one hit, In fact, it's far better for the program to crash in debugging than hit that constructor, as it will create appearance of working - like the situation you're in now.

The reason your code "didn't do anything different" when you added the services.AddSingleton<HttpClient>(new HttpClient());code is because of your empty constructor - since the Logger service was still not configured, DI framework couldn't match the correct constructor - so instead of getting a meaningful error, the empty constructor ran (since it always matches) - causing debugging pain and suffering .

As an aside, I recommend reading up on how DI works underneath (maybe even build out your own DI container, a very simple one, for practice. Do not use your own DI container in production.), This is a good article: by the guy that practically invented this stuff: https://martinfowler.com/articles/injection.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM