C# 在.NET内核中使用依赖项注入,同时考虑控制反转

C# 在.NET内核中使用依赖项注入,同时考虑控制反转,c#,.net-core,dependency-injection,C#,.net Core,Dependency Injection,我的目标是编写一个使用RESTAPI的.NET内核库。为此,我有几个类来管理对不同端点的调用以及队列。最终,我将拥有一个依赖于HttpClient的类,在阅读了它之后,似乎处理其生命周期的理想方法是使用依赖注入,这将导致我的问题,这更具有一般性(因此,如果您对HttpClient的看法不同,这不是问题的一部分) 假设调用是在以下类的帮助下进行的: 使用系统; 使用System.Net.Http; 使用System.Text.Json; 使用System.Threading.Tasks; 命名空间

我的目标是编写一个使用RESTAPI的.NET内核库。为此,我有几个类来管理对不同端点的调用以及队列。最终,我将拥有一个依赖于
HttpClient
的类,在阅读了它之后,似乎处理其生命周期的理想方法是使用依赖注入,这将导致我的问题,这更具有一般性(因此,如果您对HttpClient的看法不同,这不是问题的一部分)

假设调用是在以下类的帮助下进行的:

使用系统;
使用System.Net.Http;
使用System.Text.Json;
使用System.Threading.Tasks;
命名空间ProducerConsumer
{
内部类终结点句柄
{
私有只读HttpClientu HttpClient;
公共端点处理程序(HttpClient HttpClient)
{
_httpClient=httpClient??抛出新的ArgumentNullException(nameof(httpClient));
}
公共异步任务获取(命令)
{
返回await JsonDocument.ParseAsync(await_httpClient.GetStreamAsync((string)command.Parameters[“url”]);
}
}
}
因此,我想做的是依赖注入
HttpClient
服务,我可以通过调用
AddHttpClient()
到我的服务中,或者通过注入
IHttpClientFactory
(基于)

我现在的问题是,我不知道如何实际调用
Fetch()
方法,因为我无法使用new手动创建它的实例。此外,使用服务定位器模式实际上不是一个选项,因为它被认为是一种反模式。所以我似乎从根本上理解了一些错误。使用DI会很好,因为我也可以将其用于模拟服务以进行测试或在开发过程中更改某些行为


关于堆栈溢出的其他帖子暗示我没有完全理解控制反转原理。例如,如果与ASP.NET控制器进行比较,在ASP.NET控制器中也使用了依赖项注入,那么它们会以某种方式“神奇地”接收传入的请求,而不会在代码中的任何地方直接调用。我想这是我必须走的方向,但我不知道我怎么能做到。如果有人能对这些原则有所帮助。此外,如果有一种简单的方法可以将答案输入CAN,那也会有所帮助。

如果使用DI,最好使用DI创建所有类,并使用ServiceProvider获取类的实例

在您的示例中,如果在程序启动中使用ASP或someware,请在startup.cs中将类添加到服务中

public void ConfigureServices(IServiceCollection services)
{
            services.AddHttpClient()
                    .AddSingleton<EndpointAHandler>()
}

public void配置服务(IServiceCollection服务)
{
services.AddHttpClient()
.AddSingleton()
}
现在,您可以通过调用

var endpointAHandler = serviceProvider.GetService<EndpointAHandler>();
var endpointAHandler=serviceProvider.GetService();
在ASP上,您可以将IServiceProvider作为参数添加到控制器构造函数中,并使用DI获取serviceprovider


希望这能有所帮助。

为了继续这种依赖注入模式,重要的问题不是“我如何调用Fetch方法?”而是“我需要从哪里调用Fetch方法?”

您在上面创建的大致是一个类型化的HttpClient,您可能在浏览Microsoft提供的内容时遇到过它;它需要一个HttpClient实例,然后围绕该实例提供一组更严格控制的操作

当您创建类库之类的东西时,消费应用程序就有责任将该客户机注册到其自己的服务容器中,以便它可用于代码中的任何注入依赖项,或直接向客户机公开以供使用。为了实现这一点,通常的做法是为服务集合编写某种生成器或静态扩展方法,以帮助更轻松地处理该注册:

public static class MyLibraryServiceExtensions 
{

    public static IServiceCollection AddMyLibrary(this IServiceCollection services)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        services.AddHttpClient<IMyTypedClient, MyTypedClient>();
        services.AddTransient<ISomeOtherDependency, SomeOtherDependency>();
        // whatever else you need to register

        return services;
    }
}
公共静态类MyLibraryServiceExtensions
{
公共静态IServiceCollection AddMyLibrary(此IServiceCollection服务)
{
if(服务==null)
{
抛出新的ArgumentNullException(nameof(services));
}
services.AddHttpClient();
services.AddTransient();
//你还需要注册什么
返回服务;
}
}
有了它,使用者可以在启动或合成根目录期间执行
服务。AddMyLibrary()
,然后注入组件的任何位置都可以利用它们


您可以看到Microsoft自己为自己的
服务这样做。在GitHub中的AddHttpClient()
此处:

为了利用DI,您应该注册并注入
EndpointHandler
(或相关接口)。要获得更多帮助,您可能需要分享有关如何使用该类和库的更多详细信息。您只有两个选项:“依赖项注入一直向下”,这是其他人告诉您的,或者使用服务定位器模式。@devNull我可以这样做,但我还有另一个注入,实际上我不需要。调用类也不能再由它的构造函数创建(因为我在那里有一个DI),这意味着我也必须注入这个类。这条链不断升级,直到我必须在一个上层类中注入多个(多个)服务,而这个上层类本身实际上并不依赖这些服务(假设我的数据库服务只被一个底层类所需要)。以上所有课程都需要传递吗?这会比最初增加更多的依赖项吗?我想我错了…:o@LostInComputer目前看起来是这样的,但DI并没有真正让生活变得更轻松,它只是增加了很多麻烦(至少从我的个人经历来看)